aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-01-18 20:06:33 +0000
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-01-18 20:06:33 +0000
commit831b78254cfa752d5e6542542a663468e650bcb3 (patch)
treeafb0c05de53519b72564dad4e305454ce6bd65f3 /darwin-user
parentFix CDROM permission check, by Kazu <kazoo@r3.dion.ne.jp>. (diff)
downloadqemu-kvm-831b78254cfa752d5e6542542a663468e650bcb3.tar.gz
qemu-kvm-831b78254cfa752d5e6542542a663468e650bcb3.tar.bz2
qemu-kvm-831b78254cfa752d5e6542542a663468e650bcb3.zip
Darwin userspace emulation, by Pierre d'Herbemont.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2332 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'darwin-user')
-rw-r--r--darwin-user/commpage.c358
-rw-r--r--darwin-user/ioctls.h4
-rw-r--r--darwin-user/ioctls_types.h1
-rw-r--r--darwin-user/machload.c903
-rw-r--r--darwin-user/main.c922
-rw-r--r--darwin-user/mmap.c411
-rw-r--r--darwin-user/qemu.h179
-rw-r--r--darwin-user/signal.c463
-rw-r--r--darwin-user/syscall.c1315
-rw-r--r--darwin-user/syscalls.h384
10 files changed, 4940 insertions, 0 deletions
diff --git a/darwin-user/commpage.c b/darwin-user/commpage.c
new file mode 100644
index 000000000..12ee1da02
--- /dev/null
+++ b/darwin-user/commpage.c
@@ -0,0 +1,358 @@
+ /*
+ * Commpage syscalls
+ *
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mach/message.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <libkern/OSAtomic.h>
+
+#include "qemu.h"
+
+//#define DEBUG_COMMPAGE
+
+#ifdef DEBUG_COMMPAGE
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
+#else
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
+#endif
+
+/********************************************************************
+ * Commpage definitions
+ */
+#ifdef TARGET_I386
+/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */
+# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */
+# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */
+#elif defined(TARGET_PPC)
+/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */
+# define COMMPAGE_START (-8*4096)
+# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */
+#endif
+
+void do_compare_and_swap32(void *cpu_env, int num);
+void do_compare_and_swap64(void *cpu_env, int num);
+void do_add_atomic_word32(void *cpu_env, int num);
+void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1);
+void do_nanotime(void *cpu_env, int num);
+
+void unimpl_commpage(void *cpu_env, int num);
+
+typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8);
+typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1,
+ uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5,
+ uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+#define HAS_PTR 0x10
+#define NO_PTR 0x20
+#define CALL_DIRECT 0x1
+#define CALL_INDIRECT 0x2
+
+#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \
+ { #name, offset, nargs, options, (commpage_8args_function_t)func }
+
+struct commpage_entry {
+ char * name;
+ int offset;
+ int nargs;
+ char options;
+ commpage_8args_function_t function;
+};
+
+static inline int commpage_code_num(struct commpage_entry *entry)
+{
+ if((entry->options & HAS_PTR))
+ return entry->offset + 4;
+ else
+ return entry->offset;
+}
+
+static inline int commpage_is_indirect(struct commpage_entry *entry)
+{
+ return !(entry->options & CALL_DIRECT);
+}
+
+/********************************************************************
+ * Commpage entry
+ */
+static struct commpage_entry commpage_entries[] =
+{
+ COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR),
+ COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR),
+ COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR),
+ COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR),
+
+ COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT),
+ COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT),
+ COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(gettimeofday, 1, 0x2c0, do_cgettimeofday, CALL_INDIRECT),
+ COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(pthread_self, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
+
+ COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT),
+
+#ifdef TARGET_I386
+ COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT),
+#endif
+
+ COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT),
+ COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT),
+ COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT),
+
+#ifdef TARGET_I386
+ COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT),
+ COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT),
+
+ COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT),
+
+ COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT),
+#elif TARGET_PPC
+ COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT),
+#endif
+};
+
+
+/********************************************************************
+ * Commpage backdoor
+ */
+static inline void print_commpage_entry(struct commpage_entry entry)
+{
+ printf("@0x%x %s\n", entry.offset, entry.name);
+}
+
+static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry)
+{
+#ifdef TARGET_I386
+ char * commpage = (char*)(COMMPAGE_START+entry.offset);
+ int c = 0;
+ if(entry.options & HAS_PTR)
+ {
+ commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff;
+ commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff;
+ commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff;
+ commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff;
+ }
+ commpage[c++] = 0xcd;
+ commpage[c++] = 0x79; /* int 0x79 */
+ commpage[c++] = 0xc3; /* ret */
+#else
+ qerror("can't install the commpage on this arch\n");
+#endif
+}
+
+/********************************************************************
+ * Commpage initialization
+ */
+void commpage_init(void)
+{
+#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC))
+ int i;
+ void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE,
+ PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if((int)commpage != COMMPAGE_START)
+ qerror("can't allocate the commpage\n");
+
+ bzero(commpage, COMMPAGE_SIZE);
+
+ /* XXX: commpage data not handled */
+
+ for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++)
+ install_commpage_backdoor_for_entry(commpage_entries[i]);
+#else
+ /* simply map our pages so they can be executed
+ XXX: we don't really want to do that since in the ppc on ppc situation we may
+ not able to run commpages host optimized instructions (like G5's on a G5),
+ hence this is sometimes a broken fix. */
+ page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID);
+#endif
+}
+
+/********************************************************************
+ * Commpage implementation
+ */
+void do_compare_and_swap32(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX];
+ uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
+ DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
+
+ if(value && old == tswap32(*value))
+ {
+ uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
+ *value = tswap32(new);
+ /* set zf flag */
+ ((CPUX86State*)cpu_env)->eflags |= 0x40;
+ }
+ else
+ {
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value);
+ /* unset zf flag */
+ ((CPUX86State*)cpu_env)->eflags &= ~0x40;
+ }
+#else
+ qerror("do_compare_and_swap32 unimplemented");
+#endif
+}
+
+void do_compare_and_swap64(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ /* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */
+ uint64_t old, new, swapped_val;
+ uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
+ old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
+
+ DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value);
+ swapped_val = tswap64(*value);
+
+ if(old == swapped_val)
+ {
+ new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX];
+ *value = tswap64(new);
+ /* set zf flag */
+ ((CPUX86State*)cpu_env)->eflags |= 0x40;
+ }
+ else
+ {
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val);
+ ((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32);
+ /* unset zf flag */
+ ((CPUX86State*)cpu_env)->eflags &= ~0x40;
+ }
+#else
+ qerror("do_compare_and_swap64 unimplemented");
+#endif
+}
+
+void do_add_atomic_word32(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX];
+ uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX];
+ uint32_t swapped_value = tswap32(*value);
+
+ DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value);
+
+ /* old value in EAX */
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value;
+ *value = tswap32(swapped_value + amt);
+#else
+ qerror("do_add_atomic_word32 unimplemented");
+#endif
+}
+
+void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1)
+{
+#ifdef TARGET_I386
+ extern int __commpage_gettimeofday(struct timeval *);
+ DPRINTF("commpage: gettimeofday(0x%x)\n", arg1);
+ struct timeval *time = (struct timeval *)arg1;
+ int ret = __commpage_gettimeofday(time);
+ tswap32s((uint32_t*)&time->tv_sec);
+ tswap32s((uint32_t*)&time->tv_usec);
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */
+#else
+ qerror("do_gettimeofday unimplemented");
+#endif
+}
+
+void do_nanotime(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ uint64_t t = mach_absolute_time();
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff);
+ ((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff);
+#else
+ qerror("do_nanotime unimplemented");
+#endif
+}
+
+void unimpl_commpage(void *cpu_env, int num)
+{
+ gemu_log("qemu: commpage function 0x%x not implemented\n", num);
+}
+
+/********************************************************************
+ * do_commpage - called by the main cpu loop
+ */
+void
+do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8)
+{
+ int i, found = 0;
+
+ arg1 = tswap32(arg1);
+ arg2 = tswap32(arg2);
+ arg3 = tswap32(arg3);
+ arg4 = tswap32(arg4);
+ arg5 = tswap32(arg5);
+ arg6 = tswap32(arg6);
+ arg7 = tswap32(arg7);
+ arg8 = tswap32(arg8);
+
+ num = num-COMMPAGE_START-2;
+
+ for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) {
+ if( num == commpage_code_num(&commpage_entries[i]) )
+ {
+ DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
+ found = 1;
+ if(commpage_is_indirect(&commpage_entries[i]))
+ {
+ commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function;
+ function(cpu_env, num, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7, arg8);
+ }
+ else
+ {
+ commpage_entries[i].function(arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7, arg8);
+ }
+ break;
+ }
+ }
+
+ if(!found)
+ {
+ gemu_log("qemu: commpage function 0x%x not defined\n", num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(-1);
+ }
+}
diff --git a/darwin-user/ioctls.h b/darwin-user/ioctls.h
new file mode 100644
index 000000000..dc73af259
--- /dev/null
+++ b/darwin-user/ioctls.h
@@ -0,0 +1,4 @@
+ /* emulated ioctl list */
+
+ IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+ IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
diff --git a/darwin-user/ioctls_types.h b/darwin-user/ioctls_types.h
new file mode 100644
index 000000000..63e65f031
--- /dev/null
+++ b/darwin-user/ioctls_types.h
@@ -0,0 +1 @@
+STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT) \ No newline at end of file
diff --git a/darwin-user/machload.c b/darwin-user/machload.c
new file mode 100644
index 000000000..3ba417ed0
--- /dev/null
+++ b/darwin-user/machload.c
@@ -0,0 +1,903 @@
+/*
+ * Mach-O object file loading
+ *
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "qemu.h"
+#include "disas.h"
+
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+
+//#define DEBUG_MACHLOAD
+
+#ifdef DEBUG_MACHLOAD
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
+#else
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
+#endif
+
+# define check_mach_header(x) (x.magic == MH_CIGAM)
+
+extern const char *interp_prefix;
+
+/* we don't have a good implementation for this */
+#define DONT_USE_DYLD_SHARED_MAP
+
+/* Pass extra arg to DYLD for debug */
+//#define ACTIVATE_DYLD_TRACE
+
+//#define OVERRIDE_DYLINKER
+
+#ifdef OVERRIDE_DYLINKER
+# ifdef TARGET_I386
+# define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld"
+# else
+# define DYLINKER_NAME "/usr/lib/dyld"
+# endif
+#endif
+
+/* XXX: in an include */
+struct nlist_extended
+{
+ union {
+ char *n_name;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ unsigned char n_sect;
+ short st_desc;
+ unsigned long st_value;
+ unsigned long st_size;
+};
+
+/* Print symbols in gdb */
+void *macho_text_sect = 0;
+int macho_offset = 0;
+
+int load_object(const char *filename, struct target_pt_regs * regs, void ** mh);
+void qerror(const char *format, ...);
+#ifdef TARGET_I386
+typedef struct mach_i386_thread_state {
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ unsigned int edi;
+ unsigned int esi;
+ unsigned int ebp;
+ unsigned int esp;
+ unsigned int ss;
+ unsigned int eflags;
+ unsigned int eip;
+ unsigned int cs;
+ unsigned int ds;
+ unsigned int es;
+ unsigned int fs;
+ unsigned int gs;
+} mach_i386_thread_state_t;
+
+void bswap_i386_thread_state(struct mach_i386_thread_state *ts)
+{
+ bswap32s((uint32_t*)&ts->eax);
+ bswap32s((uint32_t*)&ts->ebx);
+ bswap32s((uint32_t*)&ts->ecx);
+ bswap32s((uint32_t*)&ts->edx);
+ bswap32s((uint32_t*)&ts->edi);
+ bswap32s((uint32_t*)&ts->esi);
+ bswap32s((uint32_t*)&ts->ebp);
+ bswap32s((uint32_t*)&ts->esp);
+ bswap32s((uint32_t*)&ts->ss);
+ bswap32s((uint32_t*)&ts->eflags);
+ bswap32s((uint32_t*)&ts->eip);
+ bswap32s((uint32_t*)&ts->cs);
+ bswap32s((uint32_t*)&ts->ds);
+ bswap32s((uint32_t*)&ts->es);
+ bswap32s((uint32_t*)&ts->fs);
+ bswap32s((uint32_t*)&ts->gs);
+}
+#define target_thread_state mach_i386_thread_state
+#define TARGET_CPU_TYPE CPU_TYPE_I386
+#define TARGET_CPU_NAME "i386"
+#endif
+
+#ifdef TARGET_PPC
+struct mach_ppc_thread_state {
+ unsigned int srr0; /* Instruction address register (PC) */
+ unsigned int srr1; /* Machine state register (supervisor) */
+ unsigned int r0;
+ unsigned int r1;
+ unsigned int r2;
+ unsigned int r3;
+ unsigned int r4;
+ unsigned int r5;
+ unsigned int r6;
+ unsigned int r7;
+ unsigned int r8;
+ unsigned int r9;
+ unsigned int r10;
+ unsigned int r11;
+ unsigned int r12;
+ unsigned int r13;
+ unsigned int r14;
+ unsigned int r15;
+ unsigned int r16;
+ unsigned int r17;
+ unsigned int r18;
+ unsigned int r19;
+ unsigned int r20;
+ unsigned int r21;
+ unsigned int r22;
+ unsigned int r23;
+ unsigned int r24;
+ unsigned int r25;
+ unsigned int r26;
+ unsigned int r27;
+ unsigned int r28;
+ unsigned int r29;
+ unsigned int r30;
+ unsigned int r31;
+
+ unsigned int cr; /* Condition register */
+ unsigned int xer; /* User's integer exception register */
+ unsigned int lr; /* Link register */
+ unsigned int ctr; /* Count register */
+ unsigned int mq; /* MQ register (601 only) */
+
+ unsigned int vrsave; /* Vector Save Register */
+};
+
+void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts)
+{
+ bswap32s((uint32_t*)&ts->srr0);
+ bswap32s((uint32_t*)&ts->srr1);
+ bswap32s((uint32_t*)&ts->r0);
+ bswap32s((uint32_t*)&ts->r1);
+ bswap32s((uint32_t*)&ts->r2);
+ bswap32s((uint32_t*)&ts->r3);
+ bswap32s((uint32_t*)&ts->r4);
+ bswap32s((uint32_t*)&ts->r5);
+ bswap32s((uint32_t*)&ts->r6);
+ bswap32s((uint32_t*)&ts->r7);
+ bswap32s((uint32_t*)&ts->r8);
+ bswap32s((uint32_t*)&ts->r9);
+ bswap32s((uint32_t*)&ts->r10);
+ bswap32s((uint32_t*)&ts->r11);
+ bswap32s((uint32_t*)&ts->r12);
+ bswap32s((uint32_t*)&ts->r13);
+ bswap32s((uint32_t*)&ts->r14);
+ bswap32s((uint32_t*)&ts->r15);
+ bswap32s((uint32_t*)&ts->r16);
+ bswap32s((uint32_t*)&ts->r17);
+ bswap32s((uint32_t*)&ts->r18);
+ bswap32s((uint32_t*)&ts->r19);
+ bswap32s((uint32_t*)&ts->r20);
+ bswap32s((uint32_t*)&ts->r21);
+ bswap32s((uint32_t*)&ts->r22);
+ bswap32s((uint32_t*)&ts->r23);
+ bswap32s((uint32_t*)&ts->r24);
+ bswap32s((uint32_t*)&ts->r25);
+ bswap32s((uint32_t*)&ts->r26);
+ bswap32s((uint32_t*)&ts->r27);
+ bswap32s((uint32_t*)&ts->r28);
+ bswap32s((uint32_t*)&ts->r29);
+ bswap32s((uint32_t*)&ts->r30);
+ bswap32s((uint32_t*)&ts->r31);
+
+ bswap32s((uint32_t*)&ts->cr);
+ bswap32s((uint32_t*)&ts->xer);
+ bswap32s((uint32_t*)&ts->lr);
+ bswap32s((uint32_t*)&ts->ctr);
+ bswap32s((uint32_t*)&ts->mq);
+
+ bswap32s((uint32_t*)&ts->vrsave);
+}
+
+#define target_thread_state mach_ppc_thread_state
+#define TARGET_CPU_TYPE CPU_TYPE_POWERPC
+#define TARGET_CPU_NAME "PowerPC"
+#endif
+
+struct target_thread_command {
+ unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */
+ unsigned long cmdsize; /* total size of this command */
+ unsigned long flavor; /* flavor of thread state */
+ unsigned long count; /* count of longs in thread state */
+ struct target_thread_state state; /* thread state for this flavor */
+};
+
+void bswap_tc(struct target_thread_command *tc)
+{
+ bswap32s((uint32_t*)(&tc->flavor));
+ bswap32s((uint32_t*)&tc->count);
+#if defined(TARGET_I386)
+ bswap_i386_thread_state(&tc->state);
+#elif defined(TARGET_PPC)
+ bswap_ppc_thread_state(&tc->state);
+#else
+# error unknown TARGET_CPU_TYPE
+#endif
+}
+
+void bswap_mh(struct mach_header *mh)
+{
+ bswap32s((uint32_t*)(&mh->magic));
+ bswap32s((uint32_t*)&mh->cputype);
+ bswap32s((uint32_t*)&mh->cpusubtype);
+ bswap32s((uint32_t*)&mh->filetype);
+ bswap32s((uint32_t*)&mh->ncmds);
+ bswap32s((uint32_t*)&mh->sizeofcmds);
+ bswap32s((uint32_t*)&mh->flags);
+}
+
+void bswap_lc(struct load_command *lc)
+{
+ bswap32s((uint32_t*)&lc->cmd);
+ bswap32s((uint32_t*)&lc->cmdsize);
+}
+
+
+void bswap_fh(struct fat_header *fh)
+{
+ bswap32s((uint32_t*)&fh->magic);
+ bswap32s((uint32_t*)&fh->nfat_arch);
+}
+
+void bswap_fa(struct fat_arch *fa)
+{
+ bswap32s((uint32_t*)&fa->cputype);
+ bswap32s((uint32_t*)&fa->cpusubtype);
+ bswap32s((uint32_t*)&fa->offset);
+ bswap32s((uint32_t*)&fa->size);
+ bswap32s((uint32_t*)&fa->align);
+}
+
+void bswap_segcmd(struct segment_command *sc)
+{
+ bswap32s((uint32_t*)&sc->vmaddr);
+ bswap32s((uint32_t*)&sc->vmsize);
+ bswap32s((uint32_t*)&sc->fileoff);
+ bswap32s((uint32_t*)&sc->filesize);
+ bswap32s((uint32_t*)&sc->maxprot);
+ bswap32s((uint32_t*)&sc->initprot);
+ bswap32s((uint32_t*)&sc->nsects);
+ bswap32s((uint32_t*)&sc->flags);
+}
+
+void bswap_symtabcmd(struct symtab_command *stc)
+{
+ bswap32s((uint32_t*)&stc->cmd);
+ bswap32s((uint32_t*)&stc->cmdsize);
+ bswap32s((uint32_t*)&stc->symoff);
+ bswap32s((uint32_t*)&stc->nsyms);
+ bswap32s((uint32_t*)&stc->stroff);
+ bswap32s((uint32_t*)&stc->strsize);
+}
+
+void bswap_sym(struct nlist *n)
+{
+ bswap32s((uint32_t*)&n->n_un.n_strx);
+ bswap16s((uint16_t*)&n->n_desc);
+ bswap32s((uint32_t*)&n->n_value);
+}
+
+int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap)
+{
+ int entry;
+ if(need_bswap)
+ bswap_tc(tc);
+#if defined(TARGET_I386)
+ entry = tc->state.eip;
+ DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n",
+ tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp,
+ tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es,
+ tc->state.fs, tc->state.gs );
+#define reg_copy(reg) regs->reg = tc->state.reg
+ if(regs)
+ {
+ reg_copy(eax);
+ reg_copy(ebx);
+ reg_copy(ecx);
+ reg_copy(edx);
+
+ reg_copy(edi);
+ reg_copy(esi);
+
+ reg_copy(ebp);
+ reg_copy(esp);
+
+ reg_copy(eflags);
+ reg_copy(eip);
+ /*
+ reg_copy(ss);
+ reg_copy(cs);
+ reg_copy(ds);
+ reg_copy(es);
+ reg_copy(fs);
+ reg_copy(gs);*/
+ }
+#undef reg_copy
+#elif defined(TARGET_PPC)
+ entry = tc->state.srr0;
+#endif
+ DPRINTF("load_thread: entry 0x%x\n", entry);
+ return entry;
+}
+
+int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap)
+{
+ int size;
+ char * dylinker_name;
+ size = dc->cmdsize - sizeof(struct dylinker_command);
+
+ if(need_bswap)
+ dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc);
+ else
+ dylinker_name = (char*)((dc->name.offset)+(int)dc);
+
+#ifdef OVERRIDE_DYLINKER
+ dylinker_name = DYLINKER_NAME;
+#else
+ if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1)
+ qerror("can't allocate the new dylinker name\n");
+#endif
+
+ DPRINTF("dylinker_name %s\n", dylinker_name);
+ return load_object(dylinker_name, NULL, NULL);
+}
+
+int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide)
+{
+ unsigned long addr = sc->vmaddr;
+ unsigned long size = sc->filesize;
+ unsigned long error = 0;
+
+ if(need_bswap)
+ bswap_segcmd(sc);
+
+ if(sc->vmaddr == 0)
+ {
+ DPRINTF("load_segment: sc->vmaddr == 0 returning\n");
+ return -1;
+ }
+
+ if (strcmp(sc->segname, "__PAGEZERO") == 0)
+ {
+ DPRINTF("load_segment: __PAGEZERO returning\n");
+ return -1;
+ }
+
+ /* Right now mmap memory */
+ /* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */
+ DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide);
+
+ if(sc->filesize > 0)
+ {
+ int opt = 0;
+
+ if(fixed)
+ opt |= MAP_FIXED;
+
+ DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide);
+
+ addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff);
+
+ if(addr==-1)
+ qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
+
+ error = addr-sc->vmaddr;
+ }
+ else
+ {
+ addr = sc->vmaddr+slide;
+ error = slide;
+ }
+
+ if(sc->vmsize > sc->filesize)
+ {
+ addr += sc->filesize;
+ size = sc->vmsize-sc->filesize;
+ addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if(addr==-1)
+ qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
+ }
+
+ return error;
+}
+
+void *load_data(int fd, long offset, unsigned int size)
+{
+ char *data;
+
+ data = malloc(size);
+ if (!data)
+ return NULL;
+ lseek(fd, offset, SEEK_SET);
+ if (read(fd, data, size) != size) {
+ free(data);
+ return NULL;
+ }
+ return data;
+}
+
+/* load a mach-o object file */
+int load_object(const char *filename, struct target_pt_regs * regs, void ** mh)
+{
+ int need_bswap = 0;
+ int entry_point = 0;
+ int dyld_entry_point = 0;
+ int slide, mmapfixed;
+ int fd;
+ struct load_command *lcmds, *lc;
+ int is_fat = 0;
+ unsigned int i, magic;
+ int mach_hdr_pos = 0;
+ struct mach_header mach_hdr;
+
+ /* for symbol lookup whith -d flag. */
+ struct symtab_command * symtabcmd = 0;
+ struct nlist_extended *symtab, *sym;
+ struct nlist *symtab_std, *syment;
+ char *strtab;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ qerror("can't open file '%s'", filename);
+
+ /* Read magic header. */
+ if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
+ qerror("unable to read Magic of '%s'", filename);
+
+ /* Check Mach identification. */
+ if(magic == MH_MAGIC)
+ {
+ is_fat = 0;
+ need_bswap = 0;
+ } else if (magic == MH_CIGAM)
+ {
+ is_fat = 0;
+ need_bswap = 1;
+ } else if (magic == FAT_MAGIC)
+ {
+ is_fat = 1;
+ need_bswap = 0;
+ } else if (magic == FAT_CIGAM)
+ {
+ is_fat = 1;
+ need_bswap = 1;
+ }
+ else
+ qerror("Not a Mach-O file.", filename);
+
+ DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]");
+ if(is_fat)
+ {
+ int found = 0;
+ struct fat_header fh;
+ struct fat_arch *fa;
+
+ lseek(fd, 0, SEEK_SET);
+
+ /* Read Fat header. */
+ if (read(fd, &fh, sizeof (fh)) != sizeof (fh))
+ qerror("unable to read file header");
+
+ if(need_bswap)
+ bswap_fh(&fh);
+
+ /* Read Fat Arch. */
+ fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch);
+
+ if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch)
+ qerror("unable to read file header");
+
+ for( i = 0; i < fh.nfat_arch; i++, fa++)
+ {
+ if(need_bswap)
+ bswap_fa(fa);
+ if(fa->cputype == TARGET_CPU_TYPE)
+ {
+ mach_hdr_pos = fa->offset;
+ lseek(fd, mach_hdr_pos, SEEK_SET);
+
+ /* Read Mach header. */
+
+ if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header))
+ qerror("unable to read file header");
+
+ if(mach_hdr.magic == MH_MAGIC)
+ need_bswap = 0;
+ else if (mach_hdr.magic == MH_CIGAM)
+ need_bswap = 1;
+ else
+ qerror("Invalid mach header in Fat Mach-O File");
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME);
+ }
+ else
+ {
+ lseek(fd, 0, SEEK_SET);
+ /* Read Mach header */
+ if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
+ qerror("%s: unable to read file header", filename);
+ }
+
+ if(need_bswap)
+ bswap_mh(&mach_hdr);
+
+ if ((mach_hdr.cputype) != TARGET_CPU_TYPE)
+ qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME);
+
+
+ switch(mach_hdr.filetype)
+ {
+ case MH_EXECUTE: break;
+ case MH_FVMLIB:
+ case MH_DYLIB:
+ case MH_DYLINKER: break;
+ default:
+ qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype);
+ }
+
+ /* read segment headers */
+ lcmds = malloc(mach_hdr.sizeofcmds);
+
+ if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds)
+ qerror("%s: unable to read load_command", filename);
+ slide = 0;
+ mmapfixed = 0;
+ for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++)
+ {
+
+ if(need_bswap)
+ bswap_lc(lc);
+ switch(lc->cmd)
+ {
+ case LC_SEGMENT:
+ /* The main_exe can't be relocated */
+ if(mach_hdr.filetype == MH_EXECUTE)
+ mmapfixed = 1;
+
+ slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide);
+
+ /* other segment must be mapped according to slide exactly, if load_segment did something */
+ if(slide != -1)
+ mmapfixed = 1;
+ else
+ slide = 0; /* load_segment didn't map the segment */
+
+ if(mach_hdr.filetype == MH_EXECUTE && slide != 0)
+ qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide);
+
+ if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0)
+ {
+ /* Text section */
+ if(mach_hdr.filetype == MH_EXECUTE)
+ {
+ /* return the mach_header */
+ *mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
+ }
+ else
+ {
+ /* it is dyld save the section for gdb, we will be interested in dyld symbol
+ while debuging */
+ macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
+ macho_offset = slide;
+ }
+ }
+ break;
+ case LC_LOAD_DYLINKER:
+ dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap );
+ break;
+ case LC_LOAD_DYLIB:
+ /* dyld will do that for us */
+ break;
+ case LC_THREAD:
+ case LC_UNIXTHREAD:
+ {
+ struct target_pt_regs * _regs;
+ if(mach_hdr.filetype == MH_DYLINKER)
+ _regs = regs;
+ else
+ _regs = 0;
+ entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap );
+ }
+ break;
+ case LC_SYMTAB:
+ /* Save the symtab and strtab */
+ symtabcmd = (struct symtab_command *)lc;
+ break;
+ case LC_ID_DYLINKER:
+ case LC_ID_DYLIB:
+ case LC_UUID:
+ case LC_DYSYMTAB:
+ case LC_TWOLEVEL_HINTS:
+ case LC_PREBIND_CKSUM:
+ case LC_SUB_LIBRARY:
+ break;
+ default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename);
+ }
+ lc = (struct load_command*)((int)(lc)+(lc->cmdsize));
+ }
+
+ if(symtabcmd)
+ {
+ if(need_bswap)
+ bswap_symtabcmd(symtabcmd);
+
+ symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist));
+ strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize);
+
+ symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms);
+
+ if(need_bswap)
+ {
+ for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++)
+ bswap_sym(syment);
+ }
+
+ for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++)
+ {
+ struct nlist *sym_follow, *sym_next = 0;
+ unsigned int j;
+ memset(sym, 0, sizeof(*sym));
+
+ sym->n_type = syment->n_type;
+ if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
+ continue;
+
+ memcpy(sym, syment, sizeof(*syment));
+
+ /* Find the following symbol in order to get the current symbol size */
+ for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) {
+ if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
+ continue;
+ if(!sym_next) {
+ sym_next = sym_follow;
+ continue;
+ }
+ if(!(sym_next->n_value > sym_follow->n_value))
+ continue;
+ sym_next = sym_follow;
+ }
+ if(sym_next)
+ sym->st_size = sym_next->n_value - sym->st_value;
+ else
+ sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */
+
+ sym->st_value += slide;
+ }
+
+ free((void*)symtab_std);
+
+ {
+ DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms);
+ struct syminfo *s;
+ s = malloc(sizeof(*s));
+ s->disas_symtab = symtab;
+ s->disas_strtab = strtab;
+ s->disas_num_syms = symtabcmd->nsyms;
+ s->next = syminfos;
+ syminfos = s;
+ }
+ }
+ close(fd);
+ if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point)
+ return dyld_entry_point;
+ else
+ return entry_point+slide;
+}
+
+extern unsigned long stack_size;
+
+unsigned long setup_arg_pages(void * mh, char ** argv, char ** env)
+{
+ unsigned long stack_base, error, size;
+ int i;
+ int * stack;
+ int argc, envc;
+
+ /* Create enough stack to hold everything. If we don't use
+ * it for args, we'll use it for something else...
+ */
+ size = stack_size;
+
+ error = target_mmap(0,
+ size + qemu_host_page_size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0);
+ if (error == -1)
+ qerror("stk mmap");
+
+ /* we reserve one extra page at the top of the stack as guard */
+ target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
+
+ stack_base = error + size;
+ stack = (void*)stack_base;
+/*
+ * | STRING AREA |
+ * +-------------+
+ * | 0 |
+* +-------------+
+ * | apple[n] |
+ * +-------------+
+ * :
+ * +-------------+
+ * | apple[0] |
+ * +-------------+
+ * | 0 |
+ * +-------------+
+ * | env[n] |
+ * +-------------+
+ * :
+ * :
+ * +-------------+
+ * | env[0] |
+ * +-------------+
+ * | 0 |
+ * +-------------+
+ * | arg[argc-1] |
+ * +-------------+
+ * :
+ * :
+ * +-------------+
+ * | arg[0] |
+ * +-------------+
+ * | argc |
+ * +-------------+
+ * sp-> | mh | address of where the a.out's file offset 0 is in memory
+ * +-------------+
+*/
+ /* Construct the stack Stack grows down */
+ stack--;
+
+ /* XXX: string should go up there */
+
+ *stack = 0;
+ stack--;
+
+ /* Push the absolute path of our executable */
+ DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]);
+ stl(stack, (int) argv[0]);
+
+ stack--;
+
+ stl(stack, 0);
+ stack--;
+
+ /* Get envc */
+ for(envc = 0; env[envc]; envc++);
+
+ for(i = envc-1; i >= 0; i--)
+ {
+ DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]);
+ stl(stack, (int)env[i]);
+ stack--;
+
+ /* XXX: remove that when string will be on top of the stack */
+ page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID);
+ }
+
+ /* Add on the stack the interp_prefix choosen if so */
+ if(interp_prefix[0])
+ {
+ char *dyld_root;
+ asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix);
+ page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID);
+
+ stl(stack, (int)dyld_root);
+ stack--;
+ }
+
+#ifdef DONT_USE_DYLD_SHARED_MAP
+ {
+ char *shared_map_mode;
+ asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid");
+ page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID);
+
+ stl(stack, (int)shared_map_mode);
+ stack--;
+ }
+#endif
+
+#ifdef ACTIVATE_DYLD_TRACE
+ char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes",
+ "DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes",
+ "DYLD_PRINT_INITIALIZERS=yes",
+ "DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" };
+
+ char ** extra_env = malloc(sizeof(extra_env_static));
+ bcopy(extra_env_static, extra_env, sizeof(extra_env_static));
+ page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID);
+
+ for(i = 0; i<9; i++)
+ {
+ DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]);
+ stl(stack, (int) extra_env[i]);
+ stack--;
+ }
+#endif
+
+ stl(stack, 0);
+ stack--;
+
+ /* Get argc */
+ for(argc = 0; argv[argc]; argc++);
+
+ for(i = argc-1; i >= 0; i--)
+ {
+ DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]);
+ stl(stack, (int) argv[i]);
+ stack--;
+
+ /* XXX: remove that when string will be on top of the stack */
+ page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID);
+ }
+
+ DPRINTF("pushing argc %d \n", argc);
+ stl(stack, argc);
+ stack--;
+
+ DPRINTF("pushing mh 0x%x \n", (int)mh);
+ stl(stack, (int) mh);
+
+ /* Stack points on the mh */
+ return (unsigned long)stack;
+}
+
+int mach_exec(const char * filename, char ** argv, char ** envp,
+ struct target_pt_regs * regs)
+{
+ int entrypoint, stack;
+ void * mh; /* the Mach Header that will be used by dyld */
+
+ DPRINTF("mach_exec at 0x%x\n", (int)mach_exec);
+
+ entrypoint = load_object(filename, regs, &mh);
+ stack = setup_arg_pages(mh, argv, envp);
+#if defined(TARGET_I386)
+ regs->eip = entrypoint;
+ regs->esp = stack;
+#elif defined(TARGET_PPC)
+ regs->nip = entrypoint;
+ regs->gpr[1] = stack;
+#endif
+ DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh);
+
+ if(!entrypoint)
+ qerror("%s: no entry point!\n", filename);
+
+ return 0;
+}
diff --git a/darwin-user/main.c b/darwin-user/main.c
new file mode 100644
index 000000000..259aab324
--- /dev/null
+++ b/darwin-user/main.c
@@ -0,0 +1,922 @@
+/*
+ * qemu user main
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+
+#define DEBUG_LOGFILE "/tmp/qemu.log"
+
+#ifdef __APPLE__
+#include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#endif
+
+#include <mach/mach_init.h>
+#include <mach/vm_map.h>
+
+const char *interp_prefix = "";
+
+asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000");
+
+/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
+ we allocate a bigger stack. Need a better solution, for example
+ by remapping the process stack directly at the right place */
+unsigned long stack_size = 512 * 1024;
+
+void qerror(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+void gemu_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+void cpu_outb(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
+}
+
+void cpu_outw(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
+}
+
+void cpu_outl(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
+}
+
+int cpu_inb(CPUState *env, int addr)
+{
+ fprintf(stderr, "inb: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_inw(CPUState *env, int addr)
+{
+ fprintf(stderr, "inw: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_inl(CPUState *env, int addr)
+{
+ fprintf(stderr, "inl: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_get_pic_interrupt(CPUState *env)
+{
+ return -1;
+}
+#ifdef TARGET_PPC
+
+static inline uint64_t cpu_ppc_get_tb (CPUState *env)
+{
+ /* TO FIX */
+ return 0;
+}
+
+uint32_t cpu_ppc_load_tbl (CPUState *env)
+{
+ return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
+}
+
+uint32_t cpu_ppc_load_tbu (CPUState *env)
+{
+ return cpu_ppc_get_tb(env) >> 32;
+}
+
+static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
+{
+ /* TO FIX */
+}
+
+void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+{
+ cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+}
+
+void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+{
+ cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
+}
+
+uint32_t cpu_ppc_load_decr (CPUState *env)
+{
+ /* TO FIX */
+ return -1;
+}
+
+void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+{
+ /* TO FIX */
+}
+
+void cpu_loop(CPUPPCState *env)
+{
+ int trapnr;
+ uint32_t ret;
+ target_siginfo_t info;
+
+ for(;;) {
+ trapnr = cpu_ppc_exec(env);
+ if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
+ trapnr != EXCP_TRACE) {
+ if (loglevel > 0) {
+ cpu_dump_state(env, logfile, fprintf, 0);
+ }
+ }
+ switch(trapnr) {
+ case EXCP_NONE:
+ break;
+ case EXCP_SYSCALL_USER:
+ /* system call */
+ if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
+ ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8], env->gpr[9], env->gpr[10]*/);
+ else if(((int)env->gpr[0])<0)
+ ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8], env->gpr[9], env->gpr[10]);
+ else
+ ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8], env->gpr[9], env->gpr[10]);
+
+ /* Unix syscall error signaling */
+ if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
+ {
+ if( (int)ret < 0 )
+ env->nip += 0;
+ else
+ env->nip += 4;
+ }
+
+ /* Return value */
+ env->gpr[3] = ret;
+ break;
+ case EXCP_RESET:
+ /* Should not happen ! */
+ fprintf(stderr, "RESET asked... Stop emulation\n");
+ if (loglevel)
+ fprintf(logfile, "RESET asked... Stop emulation\n");
+ abort();
+ case EXCP_MACHINE_CHECK:
+ fprintf(stderr, "Machine check exeption... Stop emulation\n");
+ if (loglevel)
+ fprintf(logfile, "RESET asked... Stop emulation\n");
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_OBJERR;
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ case EXCP_DSI:
+#ifndef DAR
+/* To deal with multiple qemu header version as host for the darwin-user code */
+# define DAR SPR_DAR
+#endif
+ fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
+ if (loglevel) {
+ fprintf(logfile, "Invalid data memory access: 0x%08x\n",
+ env->spr[DAR]);
+ }
+ /* Handle this via the gdb */
+ gdb_handlesig (env, SIGSEGV);
+
+ info.si_addr = (void*)env->nip;
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_ISI:
+ fprintf(stderr, "Invalid instruction fetch\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid instruction fetch\n");
+ /* Handle this via the gdb */
+ gdb_handlesig (env, SIGSEGV);
+
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_EXTERNAL:
+ /* Should not happen ! */
+ fprintf(stderr, "External interruption... Stop emulation\n");
+ if (loglevel)
+ fprintf(logfile, "External interruption... Stop emulation\n");
+ abort();
+ case EXCP_ALIGN:
+ fprintf(stderr, "Invalid unaligned memory access\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid unaligned memory access\n");
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRALN;
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_PROGRAM:
+ switch (env->error_code & ~0xF) {
+ case EXCP_FP:
+ fprintf(stderr, "Program exception\n");
+ if (loglevel)
+ fprintf(logfile, "Program exception\n");
+ /* Set FX */
+ env->fpscr[7] |= 0x8;
+ /* Finally, update FEX */
+ if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
+ ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
+ env->fpscr[7] |= 0x4;
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_FP_OX:
+ info.si_code = FPE_FLTOVF;
+ break;
+ case EXCP_FP_UX:
+ info.si_code = FPE_FLTUND;
+ break;
+ case EXCP_FP_ZX:
+ case EXCP_FP_VXZDZ:
+ info.si_code = FPE_FLTDIV;
+ break;
+ case EXCP_FP_XX:
+ info.si_code = FPE_FLTRES;
+ break;
+ case EXCP_FP_VXSOFT:
+ info.si_code = FPE_FLTINV;
+ break;
+ case EXCP_FP_VXNAN:
+ case EXCP_FP_VXISI:
+ case EXCP_FP_VXIDI:
+ case EXCP_FP_VXIMZ:
+ case EXCP_FP_VXVC:
+ case EXCP_FP_VXSQRT:
+ case EXCP_FP_VXCVI:
+ info.si_code = FPE_FLTSUB;
+ break;
+ default:
+ fprintf(stderr, "Unknown floating point exception "
+ "(%02x)\n", env->error_code);
+ if (loglevel) {
+ fprintf(logfile, "Unknown floating point exception "
+ "(%02x)\n", env->error_code & 0xF);
+ }
+ }
+ break;
+ case EXCP_INVAL:
+ fprintf(stderr, "Invalid instruction\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid instruction\n");
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_INVAL_INVAL:
+ info.si_code = ILL_ILLOPC;
+ break;
+ case EXCP_INVAL_LSWX:
+ info.si_code = ILL_ILLOPN;
+ break;
+ case EXCP_INVAL_SPR:
+ info.si_code = ILL_PRVREG;
+ break;
+ case EXCP_INVAL_FP:
+ info.si_code = ILL_COPROC;
+ break;
+ default:
+ fprintf(stderr, "Unknown invalid operation (%02x)\n",
+ env->error_code & 0xF);
+ if (loglevel) {
+ fprintf(logfile, "Unknown invalid operation (%02x)\n",
+ env->error_code & 0xF);
+ }
+ info.si_code = ILL_ILLADR;
+ break;
+ }
+ /* Handle this via the gdb */
+ gdb_handlesig (env, SIGSEGV);
+ break;
+ case EXCP_PRIV:
+ fprintf(stderr, "Privilege violation\n");
+ if (loglevel)
+ fprintf(logfile, "Privilege violation\n");
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_PRIV_OPC:
+ info.si_code = ILL_PRVOPC;
+ break;
+ case EXCP_PRIV_REG:
+ info.si_code = ILL_PRVREG;
+ break;
+ default:
+ fprintf(stderr, "Unknown privilege violation (%02x)\n",
+ env->error_code & 0xF);
+ info.si_code = ILL_PRVOPC;
+ break;
+ }
+ break;
+ case EXCP_TRAP:
+ fprintf(stderr, "Tried to call a TRAP\n");
+ if (loglevel)
+ fprintf(logfile, "Tried to call a TRAP\n");
+ abort();
+ default:
+ /* Should not happen ! */
+ fprintf(stderr, "Unknown program exception (%02x)\n",
+ env->error_code);
+ if (loglevel) {
+ fprintf(logfile, "Unknwon program exception (%02x)\n",
+ env->error_code);
+ }
+ abort();
+ }
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_NO_FP:
+ fprintf(stderr, "No floating point allowed\n");
+ if (loglevel)
+ fprintf(logfile, "No floating point allowed\n");
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_COPROC;
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_DECR:
+ /* Should not happen ! */
+ fprintf(stderr, "Decrementer exception\n");
+ if (loglevel)
+ fprintf(logfile, "Decrementer exception\n");
+ abort();
+ case EXCP_TRACE:
+ /* Pass to gdb: we use this to trace execution */
+ gdb_handlesig (env, SIGTRAP);
+ break;
+ case EXCP_FP_ASSIST:
+ /* Should not happen ! */
+ fprintf(stderr, "Floating point assist exception\n");
+ if (loglevel)
+ fprintf(logfile, "Floating point assist exception\n");
+ abort();
+ case EXCP_MTMSR:
+ /* We reloaded the msr, just go on */
+ if (msr_pr == 0) {
+ fprintf(stderr, "Tried to go into supervisor mode !\n");
+ if (loglevel)
+ fprintf(logfile, "Tried to go into supervisor mode !\n");
+ abort();
+ }
+ break;
+ case EXCP_BRANCH:
+ /* We stopped because of a jump... */
+ break;
+ case EXCP_INTERRUPT:
+ /* Don't know why this should ever happen... */
+ fprintf(stderr, "EXCP_INTERRUPT\n");
+ break;
+ case EXCP_DEBUG:
+ gdb_handlesig (env, SIGTRAP);
+ break;
+ default:
+ fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ trapnr);
+ if (loglevel) {
+ fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
+ "0x%02x - aborting\n", trapnr, env->error_code);
+ }
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+#endif
+
+
+#ifdef TARGET_I386
+
+/***********************************************************/
+/* CPUX86 core interface */
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+ return cpu_get_real_ticks();
+}
+
+void
+write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags)
+{
+ unsigned int e1, e2;
+ e1 = (addr << 16) | (limit & 0xffff);
+ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+ e2 |= flags;
+ stl((uint8_t *)ptr, e1);
+ stl((uint8_t *)ptr + 4, e2);
+}
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+ unsigned long addr, unsigned int sel)
+{
+ unsigned int e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ stl((uint8_t *)ptr, e1);
+ stl((uint8_t *)ptr + 4, e2);
+}
+
+#define GDT_TABLE_SIZE 14
+#define LDT_TABLE_SIZE 15
+#define IDT_TABLE_SIZE 256
+#define TSS_SIZE 104
+uint64_t gdt_table[GDT_TABLE_SIZE];
+uint64_t ldt_table[LDT_TABLE_SIZE];
+uint64_t idt_table[IDT_TABLE_SIZE];
+uint32_t tss[TSS_SIZE];
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+/* ABI convention: after a syscall if there was an error the CF flag is set */
+static inline set_error(CPUX86State *env, int ret)
+{
+ if(ret<0)
+ env->eflags = env->eflags | 0x1;
+ else
+ env->eflags &= ~0x1;
+ env->regs[R_EAX] = ret;
+}
+
+void cpu_loop(CPUX86State *env)
+{
+ int trapnr;
+ int ret;
+ uint8_t *pc;
+ target_siginfo_t info;
+
+ for(;;) {
+ trapnr = cpu_x86_exec(env);
+ uint32_t *params = (uint32_t *)env->regs[R_ESP];
+ switch(trapnr) {
+ case 0x79: /* Our commpage hack back door exit is here */
+ do_commpage(env, env->eip, *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8));
+ break;
+ case 0x81: /* mach syscall */
+ {
+ ret = do_mach_syscall(env, env->regs[R_EAX],
+ *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8));
+ set_error(env, ret);
+ break;
+ }
+ case 0x90: /* unix backdoor */
+ {
+ /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/
+ int saved_stack = env->regs[R_ESP];
+ env->regs[R_ESP] = env->regs[R_ECX];
+
+ ret = do_unix_syscall(env, env->regs[R_EAX]);
+
+ env->regs[R_ECX] = env->regs[R_ESP];
+ env->regs[R_ESP] = saved_stack;
+
+ set_error(env, ret);
+ break;
+ }
+ case 0x80: /* unix syscall */
+ {
+ ret = do_unix_syscall(env, env->regs[R_EAX]/*,
+ *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8)*/);
+ set_error(env, ret);
+ break;
+ }
+ case 0x82: /* thread syscall */
+ {
+ ret = do_thread_syscall(env, env->regs[R_EAX],
+ *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8));
+ set_error(env, ret);
+ break;
+ }
+ case EXCP0B_NOSEG:
+ case EXCP0C_STACK:
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_NOOP;
+ info.si_addr = 0;
+ gdb_handlesig (env, SIGBUS);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP0D_GPF:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_NOOP;
+ info.si_addr = 0;
+ gdb_handlesig (env, SIGSEGV);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP0E_PAGE:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ if (!(env->error_code & 1))
+ info.si_code = SEGV_MAPERR;
+ else
+ info.si_code = SEGV_ACCERR;
+ info.si_addr = (void*)env->cr[2];
+ gdb_handlesig (env, SIGSEGV);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP00_DIVZ:
+ /* division by zero */
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = FPE_INTDIV;
+ info.si_addr = (void*)env->eip;
+ gdb_handlesig (env, SIGFPE);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP01_SSTP:
+ case EXCP03_INT3:
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+ info.si_addr = (void*)env->eip;
+ gdb_handlesig (env, SIGTRAP);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP04_INTO:
+ case EXCP05_BOUND:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_NOOP;
+ info.si_addr = 0;
+ gdb_handlesig (env, SIGSEGV);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP06_ILLOP:
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPN;
+ info.si_addr = (void*)env->eip;
+ gdb_handlesig (env, SIGILL);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig (env, SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+ queue_signal(info.si_signo, &info);
+ }
+ }
+ break;
+ default:
+ pc = (void*)(env->segs[R_CS].base + env->eip);
+ fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+ (long)pc, trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+#endif
+
+void usage(void)
+{
+ printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
+ "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
+ "Darwin CPU emulator (compiled for %s emulation)\n"
+ "\n"
+ "-h print this help\n"
+ "-L path set the elf interpreter prefix (default=%s)\n"
+ "-s size set the stack size in bytes (default=%ld)\n"
+ "\n"
+ "debug options:\n"
+#ifdef USE_CODE_COPY
+ "-no-code-copy disable code copy acceleration\n"
+#endif
+ "-d options activate log (logfile=%s)\n"
+ "-g wait for gdb on port 1234\n"
+ "-p pagesize set the host page size to 'pagesize'\n",
+ TARGET_ARCH,
+ interp_prefix,
+ stack_size,
+ DEBUG_LOGFILE);
+ _exit(1);
+}
+
+/* XXX: currently only used for async signals (see signal.c) */
+CPUState *global_env;
+/* used only if single thread */
+CPUState *cpu_single_env = NULL;
+
+/* used to free thread contexts */
+TaskState *first_task_state;
+
+int main(int argc, char **argv)
+{
+ const char *filename;
+ struct target_pt_regs regs1, *regs = &regs1;
+ TaskState ts1, *ts = &ts1;
+ CPUState *env;
+ int optind;
+ short use_gdbstub = 0;
+ const char *r;
+
+ if (argc <= 1)
+ usage();
+
+ /* init debug */
+ cpu_set_log_filename(DEBUG_LOGFILE);
+
+ optind = 1;
+ for(;;) {
+ if (optind >= argc)
+ break;
+ r = argv[optind];
+ if (r[0] != '-')
+ break;
+ optind++;
+ r++;
+ if (!strcmp(r, "-")) {
+ break;
+ } else if (!strcmp(r, "d")) {
+ int mask;
+ CPULogItem *item;
+
+ if (optind >= argc)
+ break;
+
+ r = argv[optind++];
+ mask = cpu_str_to_log_mask(r);
+ if (!mask) {
+ printf("Log items (comma separated):\n");
+ for(item = cpu_log_items; item->mask != 0; item++) {
+ printf("%-10s %s\n", item->name, item->help);
+ }
+ exit(1);
+ }
+ cpu_set_log(mask);
+ } else if (!strcmp(r, "s")) {
+ r = argv[optind++];
+ stack_size = strtol(r, (char **)&r, 0);
+ if (stack_size <= 0)
+ usage();
+ if (*r == 'M')
+ stack_size *= 1024 * 1024;
+ else if (*r == 'k' || *r == 'K')
+ stack_size *= 1024;
+ } else if (!strcmp(r, "L")) {
+ interp_prefix = argv[optind++];
+ } else if (!strcmp(r, "p")) {
+ qemu_host_page_size = atoi(argv[optind++]);
+ if (qemu_host_page_size == 0 ||
+ (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+ fprintf(stderr, "page size must be a power of two\n");
+ exit(1);
+ }
+ } else
+ if (!strcmp(r, "g")) {
+ use_gdbstub = 1;
+ } else
+#ifdef USE_CODE_COPY
+ if (!strcmp(r, "no-code-copy")) {
+ code_copy_enabled = 0;
+ } else
+#endif
+ {
+ usage();
+ }
+ }
+ if (optind >= argc)
+ usage();
+ filename = argv[optind];
+
+ /* Zero out regs */
+ memset(regs, 0, sizeof(struct target_pt_regs));
+
+#if 0
+ /* Scan interp_prefix dir for replacement files. */
+ init_paths(interp_prefix);
+#endif
+
+ /* NOTE: we need to init the CPU at this stage to get
+ qemu_host_page_size */
+ env = cpu_init();
+
+ printf("Starting %s with qemu\n----------------\n", filename);
+
+ commpage_init();
+
+ if (mach_exec(filename, argv+optind, environ, regs) != 0) {
+ printf("Error loading %s\n", filename);
+ _exit(1);
+ }
+
+ syscall_init();
+ signal_init();
+ global_env = env;
+
+ /* build Task State */
+ memset(ts, 0, sizeof(TaskState));
+ env->opaque = ts;
+ ts->used = 1;
+ env->user_mode_only = 1;
+
+#if defined(TARGET_I386)
+ cpu_x86_set_cpl(env, 3);
+
+ env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+ env->hflags |= HF_PE_MASK;
+
+ if (env->cpuid_features & CPUID_SSE) {
+ env->cr[4] |= CR4_OSFXSR_MASK;
+ env->hflags |= HF_OSFXSR_MASK;
+ }
+
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags |= IF_MASK;
+
+ /* darwin register setup */
+ env->regs[R_EAX] = regs->eax;
+ env->regs[R_EBX] = regs->ebx;
+ env->regs[R_ECX] = regs->ecx;
+ env->regs[R_EDX] = regs->edx;
+ env->regs[R_ESI] = regs->esi;
+ env->regs[R_EDI] = regs->edi;
+ env->regs[R_EBP] = regs->ebp;
+ env->regs[R_ESP] = regs->esp;
+ env->eip = regs->eip;
+
+ /* Darwin LDT setup */
+ /* 2 - User code segment
+ 3 - User data segment
+ 4 - User cthread */
+ bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0]));
+ env->ldt.base = (uint32_t) ldt_table;
+ env->ldt.limit = sizeof(ldt_table) - 1;
+
+ write_dt(ldt_table + 2, 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+ write_dt(ldt_table + 3, 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+ write_dt(ldt_table + 4, 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+ /* Darwin GDT setup.
+ * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86,
+ now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */
+ bzero(gdt_table, sizeof(gdt_table));
+ env->gdt.base = (uint32_t)gdt_table;
+ env->gdt.limit = sizeof(gdt_table) - 1;
+
+ /* Set up a back door to handle sysenter syscalls (unix) */
+ char * syscallbackdoor = malloc(64);
+ page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID);
+
+ int i = 0;
+ syscallbackdoor[i++] = 0xcd;
+ syscallbackdoor[i++] = 0x90; /* int 0x90 */
+ syscallbackdoor[i++] = 0x0F;
+ syscallbackdoor[i++] = 0x35; /* sysexit */
+
+ /* Darwin sysenter/sysexit setup */
+ env->sysenter_cs = 0x1; //XXX
+ env->sysenter_eip = (int)syscallbackdoor;
+ env->sysenter_esp = (int)malloc(64);
+
+ /* Darwin TSS setup
+ This must match up with GDT[4] */
+ env->tr.base = (uint32_t) tss;
+ env->tr.limit = sizeof(tss) - 1;
+ env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT);
+ stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment
+
+ /* Darwin interrupt setup */
+ bzero(idt_table, sizeof(idt_table));
+ env->idt.base = (uint32_t) idt_table;
+ env->idt.limit = sizeof(idt_table) - 1;
+ set_idt(0, 0);
+ set_idt(1, 0);
+ set_idt(2, 0);
+ set_idt(3, 3);
+ set_idt(4, 3);
+ set_idt(5, 3);
+ set_idt(6, 0);
+ set_idt(7, 0);
+ set_idt(8, 0);
+ set_idt(9, 0);
+ set_idt(10, 0);
+ set_idt(11, 0);
+ set_idt(12, 0);
+ set_idt(13, 0);
+ set_idt(14, 0);
+ set_idt(15, 0);
+ set_idt(16, 0);
+ set_idt(17, 0);
+ set_idt(18, 0);
+ set_idt(19, 0);
+ /* Syscalls are done via
+ int 0x80 (unix) (rarely used)
+ int 0x81 (mach)
+ int 0x82 (thread)
+ int 0x83 (diag) (not handled here)
+ sysenter/sysexit (unix) -> we redirect that to int 0x90 */
+ set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */
+ set_idt(0x80, 3); /* Unix Syscall */
+ set_idt(0x81, 3); /* Mach Syscalls */
+ set_idt(0x82, 3); /* thread Syscalls */
+
+ set_idt(0x90, 3); /* Unix Syscall backdoor */
+
+
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+ cpu_x86_load_seg(env, R_FS, __USER_DS);
+ cpu_x86_load_seg(env, R_GS, __USER_DS);
+
+#elif defined(TARGET_PPC)
+ {
+ int i;
+ env->nip = regs->nip;
+ for(i = 0; i < 32; i++) {
+ env->gpr[i] = regs->gpr[i];
+ }
+ }
+#else
+#error unsupported target CPU
+#endif
+
+ if (use_gdbstub) {
+ printf("Waiting for gdb Connection on port 1234...\n");
+ gdbserver_start (1234);
+ gdb_handlesig(env, 0);
+ }
+
+ cpu_loop(env);
+ /* never exits */
+ return 0;
+}
diff --git a/darwin-user/mmap.c b/darwin-user/mmap.c
new file mode 100644
index 000000000..ada613d36
--- /dev/null
+++ b/darwin-user/mmap.c
@@ -0,0 +1,411 @@
+/*
+ * mmap support for qemu
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+
+//#define DEBUG_MMAP
+
+/* NOTE: all the constants are the HOST ones */
+int target_mprotect(unsigned long start, unsigned long len, int prot)
+{
+ unsigned long end, host_start, host_end, addr;
+ int prot1, ret;
+
+#ifdef DEBUG_MMAP
+ printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
+ prot & PROT_READ ? 'r' : '-',
+ prot & PROT_WRITE ? 'w' : '-',
+ prot & PROT_EXEC ? 'x' : '-');
+#endif
+
+ if ((start & ~TARGET_PAGE_MASK) != 0)
+ return -EINVAL;
+ len = TARGET_PAGE_ALIGN(len);
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+ if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
+ return -EINVAL;
+ if (len == 0)
+ return 0;
+
+ host_start = start & qemu_host_page_mask;
+ host_end = HOST_PAGE_ALIGN(end);
+ if (start > host_start) {
+ /* handle host page containing start */
+ prot1 = prot;
+ for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(addr);
+ }
+ if (host_end == host_start + qemu_host_page_size) {
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(addr);
+ }
+ end = host_end;
+ }
+ ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
+ if (ret != 0)
+ return ret;
+ host_start += qemu_host_page_size;
+ }
+ if (end < host_end) {
+ prot1 = prot;
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(addr);
+ }
+ ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
+ prot1 & PAGE_BITS);
+ if (ret != 0)
+ return ret;
+ host_end -= qemu_host_page_size;
+ }
+
+ /* handle the pages in the middle */
+ if (host_start < host_end) {
+ ret = mprotect((void *)host_start, host_end - host_start, prot);
+ if (ret != 0)
+ return ret;
+ }
+ page_set_flags(start, start + len, prot | PAGE_VALID);
+ return 0;
+}
+
+/* map an incomplete host page */
+int mmap_frag(unsigned long host_start,
+ unsigned long start, unsigned long end,
+ int prot, int flags, int fd, unsigned long offset)
+{
+ unsigned long host_end, ret, addr;
+ int prot1, prot_new;
+
+ host_end = host_start + qemu_host_page_size;
+
+ /* get the protection of the target pages outside the mapping */
+ prot1 = 0;
+ for(addr = host_start; addr < host_end; addr++) {
+ if (addr < start || addr >= end)
+ prot1 |= page_get_flags(addr);
+ }
+
+ if (prot1 == 0) {
+ /* no page was there, so we allocate one */
+ ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
+ flags | MAP_ANONYMOUS, -1, 0);
+ if (ret == -1)
+ return ret;
+ }
+ prot1 &= PAGE_BITS;
+
+ prot_new = prot | prot1;
+ if (!(flags & MAP_ANONYMOUS)) {
+ /* msync() won't work here, so we return an error if write is
+ possible while it is a shared mapping */
+#ifndef __APPLE__
+ if ((flags & MAP_TYPE) == MAP_SHARED &&
+#else
+ if ((flags & MAP_SHARED) &&
+#endif
+ (prot & PROT_WRITE))
+ return -EINVAL;
+
+ /* adjust protection to be able to read */
+ if (!(prot1 & PROT_WRITE))
+ mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
+
+ /* read the corresponding file data */
+ pread(fd, (void *)start, end - start, offset);
+
+ /* put final protection */
+ if (prot_new != (prot1 | PROT_WRITE))
+ mprotect((void *)host_start, qemu_host_page_size, prot_new);
+ } else {
+ /* just update the protection */
+ if (prot_new != prot1) {
+ mprotect((void *)host_start, qemu_host_page_size, prot_new);
+ }
+ }
+ return 0;
+}
+
+/* NOTE: all the constants are the HOST ones */
+long target_mmap(unsigned long start, unsigned long len, int prot,
+ int flags, int fd, unsigned long offset)
+{
+ unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
+#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
+ static unsigned long last_start = 0x40000000;
+#endif
+
+#ifdef DEBUG_MMAP
+ {
+ printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
+ start, len,
+ prot & PROT_READ ? 'r' : '-',
+ prot & PROT_WRITE ? 'w' : '-',
+ prot & PROT_EXEC ? 'x' : '-');
+ if (flags & MAP_FIXED)
+ printf("MAP_FIXED ");
+ if (flags & MAP_ANONYMOUS)
+ printf("MAP_ANON ");
+#ifndef MAP_TYPE
+# define MAP_TYPE 0x3
+#endif
+ switch(flags & MAP_TYPE) {
+ case MAP_PRIVATE:
+ printf("MAP_PRIVATE ");
+ break;
+ case MAP_SHARED:
+ printf("MAP_SHARED ");
+ break;
+ default:
+ printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
+ break;
+ }
+ printf("fd=%d offset=%lx\n", fd, offset);
+ }
+#endif
+
+ if (offset & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+
+ len = TARGET_PAGE_ALIGN(len);
+ if (len == 0)
+ return start;
+ host_start = start & qemu_host_page_mask;
+
+ if (!(flags & MAP_FIXED)) {
+#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
+ /* tell the kenel to search at the same place as i386 */
+ if (host_start == 0) {
+ host_start = last_start;
+ last_start += HOST_PAGE_ALIGN(len);
+ }
+#endif
+ if (qemu_host_page_size != qemu_real_host_page_size) {
+ /* NOTE: this code is only for debugging with '-p' option */
+ /* reserve a memory area */
+ host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
+ host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (host_start == -1)
+ return host_start;
+ host_end = host_start + host_len;
+ start = HOST_PAGE_ALIGN(host_start);
+ end = start + HOST_PAGE_ALIGN(len);
+ if (start > host_start)
+ munmap((void *)host_start, start - host_start);
+ if (end < host_end)
+ munmap((void *)end, host_end - end);
+ /* use it as a fixed mapping */
+ flags |= MAP_FIXED;
+ } else {
+ /* if not fixed, no need to do anything */
+ host_offset = offset & qemu_host_page_mask;
+ host_len = len + offset - host_offset;
+ start = (long)mmap((void *)host_start, host_len,
+ prot, flags, fd, host_offset);
+ if (start == -1)
+ return start;
+ /* update start so that it points to the file position at 'offset' */
+ if (!(flags & MAP_ANONYMOUS))
+ start += offset - host_offset;
+ goto the_end1;
+ }
+ }
+
+ if (start & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+ end = start + len;
+ host_end = HOST_PAGE_ALIGN(end);
+
+ /* worst case: we cannot map the file because the offset is not
+ aligned, so we read it */
+ if (!(flags & MAP_ANONYMOUS) &&
+ (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
+ /* msync() won't work here, so we return an error if write is
+ possible while it is a shared mapping */
+#ifndef __APPLE__
+ if ((flags & MAP_TYPE) == MAP_SHARED &&
+#else
+ if ((flags & MAP_SHARED) &&
+#endif
+ (prot & PROT_WRITE))
+ return -EINVAL;
+ retaddr = target_mmap(start, len, prot | PROT_WRITE,
+ MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0);
+ if (retaddr == -1)
+ return retaddr;
+ pread(fd, (void *)start, len, offset);
+ if (!(prot & PROT_WRITE)) {
+ ret = target_mprotect(start, len, prot);
+ if (ret != 0)
+ return ret;
+ }
+ goto the_end;
+ }
+
+ /* handle the start of the mapping */
+ if (start > host_start) {
+ if (host_end == host_start + qemu_host_page_size) {
+ /* one single host page */
+ ret = mmap_frag(host_start, start, end,
+ prot, flags, fd, offset);
+ if (ret == -1)
+ return ret;
+ goto the_end1;
+ }
+ ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
+ prot, flags, fd, offset);
+ if (ret == -1)
+ return ret;
+ host_start += qemu_host_page_size;
+ }
+ /* handle the end of the mapping */
+ if (end < host_end) {
+ ret = mmap_frag(host_end - qemu_host_page_size,
+ host_end - qemu_host_page_size, host_end,
+ prot, flags, fd,
+ offset + host_end - qemu_host_page_size - start);
+ if (ret == -1)
+ return ret;
+ host_end -= qemu_host_page_size;
+ }
+
+ /* map the middle (easier) */
+ if (host_start < host_end) {
+ unsigned long offset1;
+ if (flags & MAP_ANONYMOUS)
+ offset1 = 0;
+ else
+ offset1 = offset + host_start - start;
+ ret = (long)mmap((void *)host_start, host_end - host_start,
+ prot, flags, fd, offset1);
+ if (ret == -1)
+ return ret;
+ }
+ the_end1:
+ page_set_flags(start, start + len, prot | PAGE_VALID);
+ the_end:
+#ifdef DEBUG_MMAP
+ printf("target_mmap: ret=0x%lx\n", (long)start);
+ page_dump(stdout);
+ printf("\n");
+#endif
+ return start;
+}
+
+int target_munmap(unsigned long start, unsigned long len)
+{
+ unsigned long end, host_start, host_end, addr;
+ int prot, ret;
+
+#ifdef DEBUG_MMAP
+ printf("munmap: start=0x%lx len=0x%lx\n", start, len);
+#endif
+ if (start & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+ len = TARGET_PAGE_ALIGN(len);
+ if (len == 0)
+ return -EINVAL;
+ end = start + len;
+ host_start = start & qemu_host_page_mask;
+ host_end = HOST_PAGE_ALIGN(end);
+
+ if (start > host_start) {
+ /* handle host page containing start */
+ prot = 0;
+ for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+ prot |= page_get_flags(addr);
+ }
+ if (host_end == host_start + qemu_host_page_size) {
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot |= page_get_flags(addr);
+ }
+ end = host_end;
+ }
+ if (prot != 0)
+ host_start += qemu_host_page_size;
+ }
+ if (end < host_end) {
+ prot = 0;
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot |= page_get_flags(addr);
+ }
+ if (prot != 0)
+ host_end -= qemu_host_page_size;
+ }
+
+ /* unmap what we can */
+ if (host_start < host_end) {
+ ret = munmap((void *)host_start, host_end - host_start);
+ if (ret != 0)
+ return ret;
+ }
+
+ page_set_flags(start, start + len, 0);
+ return 0;
+}
+
+/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
+ blocks which have been allocated starting on a host page */
+long target_mremap(unsigned long old_addr, unsigned long old_size,
+ unsigned long new_size, unsigned long flags,
+ unsigned long new_addr)
+{
+#ifndef __APPLE__
+ /* XXX: use 5 args syscall */
+ new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
+ if (new_addr == -1)
+ return new_addr;
+ prot = page_get_flags(old_addr);
+ page_set_flags(old_addr, old_addr + old_size, 0);
+ page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
+ return new_addr;
+#else
+ qerror("target_mremap: unsupported\n");
+#endif
+
+}
+
+int target_msync(unsigned long start, unsigned long len, int flags)
+{
+ unsigned long end;
+
+ if (start & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+ len = TARGET_PAGE_ALIGN(len);
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+ if (end == start)
+ return 0;
+
+ start &= qemu_host_page_mask;
+ return msync((void *)start, end - start, flags);
+}
+
diff --git a/darwin-user/qemu.h b/darwin-user/qemu.h
new file mode 100644
index 000000000..4d7713b50
--- /dev/null
+++ b/darwin-user/qemu.h
@@ -0,0 +1,179 @@
+#ifndef GEMU_H
+#define GEMU_H
+
+#include "thunk.h"
+
+#include <signal.h>
+#include <string.h>
+
+#include "cpu.h"
+
+#include "gdbstub.h"
+
+typedef siginfo_t target_siginfo_t;
+#define target_sigaction sigaction
+#ifdef TARGET_I386
+struct target_pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ int xds;
+ int xes;
+ long orig_eax;
+ long eip;
+ int xcs;
+ long eflags;
+ long esp;
+ int xss;
+};
+struct target_sigcontext {
+ int sc_onstack;
+ int sc_mask;
+ int sc_eax;
+ int sc_ebx;
+ int sc_ecx;
+ int sc_edx;
+ int sc_edi;
+ int sc_esi;
+ int sc_ebp;
+ int sc_esp;
+ int sc_ss;
+ int sc_eflags;
+ int sc_eip;
+ int sc_cs;
+ int sc_ds;
+ int sc_es;
+ int sc_fs;
+ int sc_gs;
+};
+
+#define __USER_CS (0x17)
+#define __USER_DS (0x1F)
+
+#elif defined(TARGET_PPC)
+struct target_pt_regs {
+ unsigned long gpr[32];
+ unsigned long nip;
+ unsigned long msr;
+ unsigned long orig_gpr3; /* Used for restarting system calls */
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long xer;
+ unsigned long ccr;
+ unsigned long mq; /* 601 only (not used at present) */
+ /* Used on APUS to hold IPL value. */
+ unsigned long trap; /* Reason for being here */
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr;
+ unsigned long result; /* Result of a system call */
+};
+
+struct target_sigcontext {
+ int sc_onstack; /* sigstack state to restore */
+ int sc_mask; /* signal mask to restore */
+ int sc_ir; /* pc */
+ int sc_psw; /* processor status word */
+ int sc_sp; /* stack pointer if sc_regs == NULL */
+ void *sc_regs; /* (kernel private) saved state */
+};
+
+#endif
+
+typedef struct TaskState {
+ struct TaskState *next;
+ int used; /* non zero if used */
+ uint8_t stack[0];
+} __attribute__((aligned(16))) TaskState;
+
+void syscall_init(void);
+long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+long do_unix_syscall(void *cpu_env, int num);
+int do_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact);
+int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
+
+void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void qerror(const char *fmt, ...);
+
+void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags);
+
+extern CPUState *global_env;
+void cpu_loop(CPUState *env);
+void init_paths(const char *prefix);
+const char *path(const char *pathname);
+
+extern int loglevel;
+extern FILE *logfile;
+
+/* commpage.c */
+void commpage_init();
+void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+/* signal.c */
+void process_pending_signals(void *cpu_env);
+void signal_init(void);
+int queue_signal(int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+long do_sigreturn(CPUState *env, int num);
+
+/* machload.c */
+int mach_exec(const char * filename, char ** argv, char ** envp,
+ struct target_pt_regs * regs);
+
+/* mmap.c */
+int target_mprotect(unsigned long start, unsigned long len, int prot);
+long target_mmap(unsigned long start, unsigned long len, int prot,
+ int flags, int fd, unsigned long offset);
+int target_munmap(unsigned long start, unsigned long len);
+long target_mremap(unsigned long old_addr, unsigned long old_size,
+ unsigned long new_size, unsigned long flags,
+ unsigned long new_addr);
+int target_msync(unsigned long start, unsigned long len, int flags);
+
+/* user access */
+
+/* XXX: todo protect every memory access */
+#define lock_user(x,y,z) (void*)(x)
+#define unlock_user(x,y,z)
+
+/* Mac OS X ABI arguments processing */
+#ifdef TARGET_I386
+static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env)
+{
+ uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i);
+ *i+=4;
+ return tswap32(*args);
+}
+static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env)
+{
+ uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i);
+ *i+=8;
+ return tswap64(*args);
+}
+#elif defined(TARGET_PPC)
+static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env)
+{
+ /* XXX: won't work when args goes on stack after gpr10 */
+ uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]);
+ *i+=4;
+ return tswap32(args);
+}
+static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env)
+{
+ /* XXX: won't work when args goes on stack after gpr10 */
+ uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]);
+ *i+=(8 << 8) + 8;
+ return tswap64(args);
+}
+#endif
+
+#endif
diff --git a/darwin-user/signal.c b/darwin-user/signal.c
new file mode 100644
index 000000000..a0b9f89dc
--- /dev/null
+++ b/darwin-user/signal.c
@@ -0,0 +1,463 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/ucontext.h>
+
+#ifdef __ia64__
+#undef uc_mcontext
+#undef uc_sigmask
+#undef uc_stack
+#undef uc_link
+#endif
+
+#include <signal.h>
+
+#include "qemu.h"
+
+#define DEBUG_SIGNAL
+
+#define MAX_SIGQUEUE_SIZE 1024
+
+struct sigqueue {
+ struct sigqueue *next;
+ target_siginfo_t info;
+};
+
+struct emulated_sigaction {
+ struct target_sigaction sa;
+ int pending; /* true if signal is pending */
+ struct sigqueue *first;
+ struct sigqueue info; /* in order to always have memory for the
+ first signal, we put it here */
+};
+
+struct sigaltstack target_sigaltstack_used = {
+ 0, 0, SA_DISABLE
+};
+
+static struct emulated_sigaction sigact_table[NSIG];
+static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+static struct sigqueue *first_free; /* first free siginfo queue entry */
+static int signal_pending; /* non zero if a signal may be pending */
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+ void *puc);
+
+
+static inline int host_to_target_signal(int sig)
+{
+ return sig;
+}
+
+static inline int target_to_host_signal(int sig)
+{
+ return sig;
+}
+
+/* siginfo conversion */
+
+
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+}
+
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
+{
+
+}
+
+void signal_init(void)
+{
+ struct sigaction act;
+ int i;
+
+ /* set all host signal handlers. ALL signals are blocked during
+ the handlers to serialize them. */
+ sigfillset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction = host_signal_handler;
+ for(i = 1; i < NSIG; i++) {
+ sigaction(i, &act, NULL);
+ }
+
+ memset(sigact_table, 0, sizeof(sigact_table));
+
+ first_free = &sigqueue_table[0];
+ for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
+ sigqueue_table[i].next = &sigqueue_table[i + 1];
+ sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
+}
+
+/* signal queue handling */
+
+static inline struct sigqueue *alloc_sigqueue(void)
+{
+ struct sigqueue *q = first_free;
+ if (!q)
+ return NULL;
+ first_free = q->next;
+ return q;
+}
+
+static inline void free_sigqueue(struct sigqueue *q)
+{
+ q->next = first_free;
+ first_free = q;
+}
+
+/* abort execution with signal */
+void __attribute((noreturn)) force_sig(int sig)
+{
+ int host_sig;
+ host_sig = target_to_host_signal(sig);
+ fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
+ sig, strsignal(host_sig));
+ _exit(-host_sig);
+}
+
+/* queue a signal so that it will be send to the virtual CPU as soon
+ as possible */
+int queue_signal(int sig, target_siginfo_t *info)
+{
+ struct emulated_sigaction *k;
+ struct sigqueue *q, **pq;
+ target_ulong handler;
+
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "queue_signal: sig=%d\n",
+ sig);
+#endif
+ k = &sigact_table[sig - 1];
+ handler = (target_ulong)k->sa.sa_handler;
+ if (handler == SIG_DFL) {
+ /* default handler : ignore some signal. The other are fatal */
+ if (sig != SIGCHLD &&
+ sig != SIGURG &&
+ sig != SIGWINCH) {
+ force_sig(sig);
+ } else {
+ return 0; /* indicate ignored */
+ }
+ } else if (handler == host_to_target_signal(SIG_IGN)) {
+ /* ignore signal */
+ return 0;
+ } else if (handler == host_to_target_signal(SIG_ERR)) {
+ force_sig(sig);
+ } else {
+ pq = &k->first;
+ if (!k->pending) {
+ /* first signal */
+ q = &k->info;
+ } else {
+ q = alloc_sigqueue();
+ if (!q)
+ return -EAGAIN;
+ while (*pq != NULL)
+ pq = &(*pq)->next;
+ }
+ *pq = q;
+ q->info = *info;
+ q->next = NULL;
+ k->pending = 1;
+ /* signal that a new signal is pending */
+ signal_pending = 1;
+ return 1; /* indicates that the signal was queued */
+ }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+ void *puc)
+{
+ int sig;
+ target_siginfo_t tinfo;
+
+ /* the CPU emulator uses some host signals to detect exceptions,
+ we we forward to it some signals */
+ if (host_signum == SIGSEGV || host_signum == SIGBUS
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+ || host_signum == SIGFPE
+#endif
+ ) {
+ if (cpu_signal_handler(host_signum, (void*)info, puc))
+ return;
+ }
+
+ /* get target signal number */
+ sig = host_to_target_signal(host_signum);
+ if (sig < 1 || sig > NSIG)
+ return;
+
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+ if (queue_signal(sig, &tinfo) == 1) {
+ /* interrupt the virtual CPU as soon as possible */
+ cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
+ }
+}
+
+int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
+{
+ /* XXX: test errors */
+ if(oss)
+ {
+ oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp);
+ oss->ss_size = tswap32(target_sigaltstack_used.ss_size);
+ oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags);
+ }
+ if(ss)
+ {
+ target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp);
+ target_sigaltstack_used.ss_size = tswap32(ss->ss_size);
+ target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags);
+ }
+ return 0;
+}
+
+int do_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact)
+{
+ struct emulated_sigaction *k;
+ struct sigaction act1;
+ int host_sig;
+
+ if (sig < 1 || sig > NSIG)
+ return -EINVAL;
+
+ k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
+ sig, (int)act, (int)oact);
+#endif
+ if (oact) {
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
+ sig, (int)act, (int)oact);
+#endif
+
+ oact->sa_handler = tswapl(k->sa.sa_handler);
+ oact->sa_flags = tswapl(k->sa.sa_flags);
+ oact->sa_mask = tswapl(k->sa.sa_mask);
+ }
+ if (act) {
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n",
+ act->sa_handler, act->sa_flags, act->sa_mask);
+#endif
+
+ k->sa.sa_handler = tswapl(act->sa_handler);
+ k->sa.sa_flags = tswapl(act->sa_flags);
+ k->sa.sa_mask = tswapl(act->sa_mask);
+ /* we update the host signal state */
+ host_sig = target_to_host_signal(sig);
+ if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction handler going to call sigaction\n",
+ act->sa_handler, act->sa_flags, act->sa_mask);
+#endif
+
+ sigfillset(&act1.sa_mask);
+ act1.sa_flags = SA_SIGINFO;
+ if (k->sa.sa_flags & SA_RESTART)
+ act1.sa_flags |= SA_RESTART;
+ /* NOTE: it is important to update the host kernel signal
+ ignore state to avoid getting unexpected interrupted
+ syscalls */
+ if (k->sa.sa_handler == SIG_IGN) {
+ act1.sa_sigaction = (void *)SIG_IGN;
+ } else if (k->sa.sa_handler == SIG_DFL) {
+ act1.sa_sigaction = (void *)SIG_DFL;
+ } else {
+ act1.sa_sigaction = host_signal_handler;
+ }
+ sigaction(host_sig, &act1, NULL);
+ }
+ }
+ return 0;
+}
+
+
+#ifdef TARGET_I386
+
+static inline void *
+get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
+{
+ /* XXX Fix that */
+ if(target_sigaltstack_used.ss_flags & SA_DISABLE)
+ {
+ int esp;
+ /* Default to using normal stack */
+ esp = env->regs[R_ESP];
+
+ return (void *)((esp - frame_size) & -8ul);
+ }
+ else
+ {
+ return target_sigaltstack_used.ss_sp;
+ }
+}
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+ void *set, CPUState *env)
+{
+ void *frame;
+ int i, err = 0;
+
+ fprintf(stderr, "setup_frame %d\n", sig);
+ frame = get_sigframe(ka, env, sizeof(*frame));
+
+ /* Set up registers for signal handler */
+ env->regs[R_ESP] = (unsigned long) frame;
+ env->eip = (unsigned long) ka->sa.sa_handler;
+
+ env->eflags &= ~TF_MASK;
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV /* , current */);
+}
+
+long do_sigreturn(CPUState *env, int num)
+{
+ int i = 0;
+ struct target_sigcontext *scp = get_int_arg(&i, env);
+ /* XXX Get current signal number */
+ /* XXX Adjust accordin to sc_onstack, sc_mask */
+ if(tswapl(scp->sc_onstack) & 0x1)
+ target_sigaltstack_used.ss_flags |= ~SA_DISABLE;
+ else
+ target_sigaltstack_used.ss_flags &= SA_DISABLE;
+ int set = tswapl(scp->sc_eax);
+ sigprocmask(SIG_SETMASK, &set, NULL);
+
+ fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx));
+ fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi));
+ fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip));
+
+ env->regs[R_EAX] = tswapl(scp->sc_eax);
+ env->regs[R_EBX] = tswapl(scp->sc_ebx);
+ env->regs[R_ECX] = tswapl(scp->sc_ecx);
+ env->regs[R_EDX] = tswapl(scp->sc_edx);
+ env->regs[R_EDI] = tswapl(scp->sc_edi);
+ env->regs[R_ESI] = tswapl(scp->sc_esi);
+ env->regs[R_EBP] = tswapl(scp->sc_ebp);
+ env->regs[R_ESP] = tswapl(scp->sc_esp);
+ env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss);
+ env->eflags = tswapl(scp->sc_eflags);
+ env->eip = tswapl(scp->sc_eip);
+ env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs);
+ env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds);
+ env->segs[R_ES].selector = (void*)tswapl(scp->sc_es);
+ env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs);
+ env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs);
+
+ /* Again, because our caller's caller will reset EAX */
+ return env->regs[R_EAX];
+}
+
+#else
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+ void *set, CPUState *env)
+{
+ fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env, int num)
+{
+ int i = 0;
+ struct target_sigcontext *scp = get_int_arg(&i, env);
+ fprintf(stderr, "do_sigreturn: not implemented\n");
+ return -ENOSYS;
+}
+
+#endif
+
+void process_pending_signals(void *cpu_env)
+{
+ struct emulated_sigaction *k;
+ struct sigqueue *q;
+ target_ulong handler;
+ int sig;
+
+ if (!signal_pending)
+ return;
+
+ k = sigact_table;
+
+ for(sig = 1; sig <= NSIG; sig++) {
+ if (k->pending)
+ goto handle_signal;
+ k++;
+ }
+
+ /* if no signal is pending, just return */
+ signal_pending = 0;
+ return;
+handle_signal:
+ #ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: process signal %d\n", sig);
+ #endif
+ /* dequeue signal */
+ q = k->first;
+ k->first = q->next;
+ if (!k->first)
+ k->pending = 0;
+
+ sig = gdb_handlesig (cpu_env, sig);
+ if (!sig) {
+ fprintf (stderr, "Lost signal\n");
+ abort();
+ }
+
+ handler = k->sa.sa_handler;
+ if (handler == SIG_DFL) {
+ /* default handler : ignore some signal. The other are fatal */
+ if (sig != SIGCHLD &&
+ sig != SIGURG &&
+ sig != SIGWINCH) {
+ force_sig(sig);
+ }
+ } else if (handler == SIG_IGN) {
+ /* ignore sig */
+ } else if (handler == SIG_ERR) {
+ force_sig(sig);
+ } else {
+
+ setup_frame(sig, k, 0, cpu_env);
+ if (k->sa.sa_flags & SA_RESETHAND)
+ k->sa.sa_handler = SIG_DFL;
+ }
+ if (q != &k->info)
+ free_sigqueue(q);
+}
+
+
diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c
new file mode 100644
index 000000000..50725e633
--- /dev/null
+++ b/darwin-user/syscall.c
@@ -0,0 +1,1315 @@
+/*
+ * Darwin syscalls
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mach/message.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+
+#include <pthread.h>
+#include <dirent.h>
+
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/dirent.h>
+#include <sys/uio.h>
+#include <sys/termios.h>
+#include <sys/ptrace.h>
+#include <net/if.h>
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <sys/attr.h>
+
+#include <mach/ndr.h>
+#include <mach/mig_errors.h>
+
+#include "qemu.h"
+
+//#define DEBUG_SYSCALL
+
+#ifdef DEBUG_SYSCALL
+# define DEBUG_FORCE_ENABLE_LOCAL() int __DEBUG_qemu_user_force_enable = 1
+# define DEBUG_BEGIN_ENABLE __DEBUG_qemu_user_force_enable = 1;
+# define DEBUG_END_ENABLE __DEBUG_qemu_user_force_enable = 0;
+
+# define DEBUG_DISABLE_ALL() static int __DEBUG_qemu_user_force_enable = 0
+# define DEBUG_ENABLE_ALL() static int __DEBUG_qemu_user_force_enable = 1
+ DEBUG_ENABLE_ALL();
+
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); \
+ if(__DEBUG_qemu_user_force_enable) fprintf(stderr, __VA_ARGS__); \
+ } while(0)
+#else
+# define DEBUG_FORCE_ENABLE_LOCAL()
+# define DEBUG_BEGIN_ENABLE
+# define DEBUG_END_ENABLE
+
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
+#endif
+
+enum {
+ bswap_out = 0,
+ bswap_in = 1
+};
+
+extern const char *interp_prefix;
+
+static inline long get_errno(long ret)
+{
+ if (ret == -1)
+ return -errno;
+ else
+ return ret;
+}
+
+static inline int is_error(long ret)
+{
+ return (unsigned long)ret >= (unsigned long)(-4096);
+}
+
+/* ------------------------------------------------------------
+ Mach syscall handling
+*/
+
+void static inline print_description_msg_header(mach_msg_header_t *hdr)
+{
+ char *name = NULL;
+ int i;
+ struct { int number; char *name; } msg_name[] =
+ {
+ /* see http://fxr.watson.org/fxr/source/compat/mach/mach_namemap.c?v=NETBSD */
+ { 200, "host_info" },
+ { 202, "host_page_size" },
+ { 206, "host_get_clock_service" },
+ { 206, "host_get_clock_service" },
+ { 206, "host_get_clock_service" },
+ { 306, "host_get_clock_service" },
+ { 3204, "mach_port_allocate" },
+ { 3206, "mach_port_deallocate" },
+ { 3404, "mach_ports_lookup" },
+ { 3409, "mach_task_get_special_port" },
+ { 3414, "mach_task_get_exception_ports" },
+ { 3418, "mach_semaphore_create" },
+ { 3504, "mach_semaphore_create" },
+ { 3509, "mach_semaphore_create" },
+ { 3518, "semaphore_create" },
+ { 3616, "thread_policy" },
+ { 3801, "vm_allocate" },
+ { 3802, "vm_deallocate" },
+ { 3802, "vm_deallocate" },
+ { 3803, "vm_protect" },
+ { 3812, "vm_map" },
+ { 4241776, "lu_message_send_id" }, /* lookupd */
+ { 4241876, "lu_message_reply_id" }, /* lookupd */
+ };
+
+ for(i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) {
+ if(msg_name[i].number == hdr->msgh_id)
+ {
+ name = msg_name[i].name;
+ break;
+ }
+ }
+ if(!name)
+ DPRINTF("unknown mach msg %d 0x%x\n", hdr->msgh_id, hdr->msgh_id);
+ else
+ DPRINTF("%s\n", name);
+#if 0
+ DPRINTF("Bits: %8x\n", hdr->msgh_bits);
+ DPRINTF("Size: %8x\n", hdr->msgh_size);
+ DPRINTF("Rmte: %8x\n", hdr->msgh_remote_port);
+ DPRINTF("Locl: %8x\n", hdr->msgh_local_port);
+ DPRINTF("Rsrv: %8x\n", hdr->msgh_reserved);
+
+ DPRINTF("Id : %8x\n", hdr->msgh_id);
+
+ NDR_record_t *ndr = (NDR_record_t *)(hdr + 1);
+ DPRINTF("hdr = %p, sizeof(hdr) = %x, NDR = %p\n", hdr, (unsigned int)sizeof(mach_msg_header_t), ndr);
+ DPRINTF("%d %d %d %d %d %d %d %d\n",
+ ndr->mig_vers, ndr->if_vers, ndr->reserved1, ndr->mig_encoding,
+ ndr->int_rep, ndr->char_rep, ndr->float_rep, ndr->reserved2);
+#endif
+}
+
+static inline void print_mach_msg_return(mach_msg_return_t ret)
+{
+ int i, found = 0;
+#define MACH_MSG_RET(msg) { msg, #msg }
+ struct { int code; char *name; } msg_name[] =
+ {
+ /* ref: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/osfmk/man/mach_msg.html */
+ /* send message */
+ MACH_MSG_RET(MACH_SEND_MSG_TOO_SMALL),
+ MACH_MSG_RET(MACH_SEND_NO_BUFFER),
+ MACH_MSG_RET(MACH_SEND_INVALID_DATA),
+ MACH_MSG_RET(MACH_SEND_INVALID_HEADER),
+ MACH_MSG_RET(MACH_SEND_INVALID_DEST),
+ MACH_MSG_RET(MACH_SEND_INVALID_NOTIFY),
+ MACH_MSG_RET(MACH_SEND_INVALID_REPLY),
+ MACH_MSG_RET(MACH_SEND_INVALID_TRAILER),
+ MACH_MSG_RET(MACH_SEND_INVALID_MEMORY),
+ MACH_MSG_RET(MACH_SEND_INVALID_RIGHT),
+ MACH_MSG_RET(MACH_SEND_INVALID_TYPE),
+ MACH_MSG_RET(MACH_SEND_INTERRUPTED),
+ MACH_MSG_RET(MACH_SEND_TIMED_OUT),
+
+ MACH_MSG_RET(MACH_RCV_BODY_ERROR),
+ MACH_MSG_RET(MACH_RCV_HEADER_ERROR),
+
+ MACH_MSG_RET(MACH_RCV_IN_SET),
+ MACH_MSG_RET(MACH_RCV_INTERRUPTED),
+
+ MACH_MSG_RET(MACH_RCV_INVALID_DATA),
+ MACH_MSG_RET(MACH_RCV_INVALID_NAME),
+ MACH_MSG_RET(MACH_RCV_INVALID_NOTIFY),
+ MACH_MSG_RET(MACH_RCV_INVALID_TRAILER),
+ MACH_MSG_RET(MACH_RCV_INVALID_TYPE),
+
+ MACH_MSG_RET(MACH_RCV_PORT_CHANGED),
+ MACH_MSG_RET(MACH_RCV_PORT_DIED),
+
+ MACH_MSG_RET(MACH_RCV_SCATTER_SMALL),
+ MACH_MSG_RET(MACH_RCV_TIMED_OUT),
+ MACH_MSG_RET(MACH_RCV_TOO_LARGE)
+ };
+#undef MACH_MSG_RET
+
+ if( ret == MACH_MSG_SUCCESS)
+ DPRINTF("MACH_MSG_SUCCESS\n");
+ else
+ {
+ for( i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) {
+ if(msg_name[0].code & ret) {
+ DPRINTF("%s ", msg_name[0].name);
+ found = 1;
+ }
+ }
+ if(!found)
+ qerror("unknow mach message ret code %d\n", ret);
+ else
+ DPRINTF("\n");
+ }
+}
+
+static inline void swap_mach_msg_header(mach_msg_header_t *hdr)
+{
+ hdr->msgh_bits = tswap32(hdr->msgh_bits);
+ hdr->msgh_size = tswap32(hdr->msgh_size);
+ hdr->msgh_remote_port = tswap32(hdr->msgh_remote_port);
+ hdr->msgh_local_port = tswap32(hdr->msgh_local_port);
+ hdr->msgh_reserved = tswap32(hdr->msgh_reserved);
+ hdr->msgh_id = tswap32(hdr->msgh_id);
+}
+
+struct complex_msg {
+ mach_msg_header_t hdr;
+ mach_msg_body_t body;
+};
+
+static inline void * swap_mach_msg_body(struct complex_msg *complex_msg, int bswap)
+{
+ mach_msg_port_descriptor_t *descr = (mach_msg_port_descriptor_t *)(complex_msg+1);
+ int i,j;
+ void *additional_data;
+
+ if(bswap == bswap_in)
+ tswap32s(&complex_msg->body.msgh_descriptor_count);
+
+ DPRINTF("body.msgh_descriptor_count %d\n", complex_msg->body.msgh_descriptor_count);
+
+ for(i = 0; i < complex_msg->body.msgh_descriptor_count; i++) {
+ switch(descr->type)
+ {
+ case MACH_MSG_PORT_DESCRIPTOR:
+ tswap32s(&descr->name);
+ descr++;
+ break;
+ case MACH_MSG_OOL_DESCRIPTOR:
+ {
+ mach_msg_ool_descriptor_t *ool = (void *)descr;
+ tswap32s((uint32_t *)&ool->address);
+ tswap32s(&ool->size);
+
+ descr = (mach_msg_port_descriptor_t *)(ool+1);
+ break;
+ }
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ {
+ mach_msg_ool_ports_descriptor_t *ool_ports = (void *)descr;
+ mach_port_name_t * port_names;
+
+ if(bswap == bswap_in)
+ {
+ tswap32s((uint32_t *)&ool_ports->address);
+ tswap32s(&ool_ports->count);
+ }
+
+ port_names = ool_ports->address;
+
+ for(j = 0; j < ool_ports->count; j++)
+ tswap32s(&port_names[j]);
+
+ if(bswap == bswap_out)
+ {
+ tswap32s((uint32_t *)&ool_ports->address);
+ tswap32s(&ool_ports->count);
+ }
+
+ descr = (mach_msg_port_descriptor_t *)(ool_ports+1);
+ break;
+ }
+ default: qerror("unknow mach msg descriptor type %x\n", descr->type);
+ }
+ }
+ if(bswap == bswap_out)
+ tswap32s(&complex_msg->body.msgh_descriptor_count);
+ additional_data = descr;
+ return additional_data;
+}
+
+static inline uint32_t target_mach_msg_trap(
+ mach_msg_header_t *hdr, uint32_t options, uint32_t send_size,
+ uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify )
+{
+ extern int mach_msg_trap(mach_msg_header_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+ mach_msg_audit_trailer_t *trailer;
+ mach_msg_id_t msg_id;
+ uint32_t ret = 0;
+ char *additional_data;
+ int i;
+
+ swap_mach_msg_header(hdr);
+
+ print_description_msg_header(hdr);
+
+ msg_id = hdr->msgh_id;
+
+ if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_in);
+ else
+ additional_data = (void*)(hdr+1);
+
+ ret = mach_msg_trap(hdr, options, send_size, rcv_size, rcv_name, time_out, notify);
+
+ print_mach_msg_return(ret);
+
+ if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_out);
+ else
+ additional_data = (void*)(hdr+1);
+
+ if( (options & MACH_RCV_MSG) && (REQUESTED_TRAILER_SIZE(options) > 0) )
+ {
+ /* XXX: the kernel always return the full trailer with MACH_SEND_MSG, so we should
+ probably always bswap it */
+ /* warning: according to Mac OS X Internals (the book) msg_size might be expressed in
+ natural_t units but according to xnu/osfmk/mach/message.h: "The size of
+ the message must be specified in bytes" */
+ trailer = (mach_msg_audit_trailer_t *)((uint8_t *)hdr + hdr->msgh_size);
+ /* XXX: Should probably do that based on the option asked by the sender, but dealing
+ with kernel answer seems more sound */
+ switch(trailer->msgh_trailer_size)
+ {
+ case sizeof(mach_msg_audit_trailer_t):
+ for(i = 0; i < 8; i++)
+ tswap32s(&trailer->msgh_audit.val[i]);
+ /* Fall in mach_msg_security_trailer_t case */
+ case sizeof(mach_msg_security_trailer_t):
+ tswap32s(&trailer->msgh_sender.val[0]);
+ tswap32s(&trailer->msgh_sender.val[1]);
+ /* Fall in mach_msg_seqno_trailer_t case */
+ case sizeof(mach_msg_seqno_trailer_t):
+ tswap32s(&trailer->msgh_seqno);
+ /* Fall in mach_msg_trailer_t case */
+ case sizeof(mach_msg_trailer_t):
+ tswap32s(&trailer->msgh_trailer_type);
+ tswap32s(&trailer->msgh_trailer_size);
+ break;
+ case 0:
+ /* Safer not to byteswap, but probably wrong */
+ break;
+ default:
+ qerror("unknow trailer type given its size %d\n", trailer->msgh_trailer_size);
+ break;
+ }
+ }
+
+ /* Special message handling */
+ switch (msg_id) {
+ case 200: /* host_info */
+ {
+ mig_reply_error_t *err = (mig_reply_error_t *)hdr;
+ struct {
+ uint32_t unknow1;
+ uint32_t maxcpu;
+ uint32_t numcpu;
+ uint32_t memsize;
+ uint32_t cpu_type;
+ uint32_t cpu_subtype;
+ } *data = (void *)(err+1);
+
+ DPRINTF("maxcpu = 0x%x\n", data->maxcpu);
+ DPRINTF("numcpu = 0x%x\n", data->maxcpu);
+ DPRINTF("memsize = 0x%x\n", data->memsize);
+
+#if defined(TARGET_I386)
+ data->cpu_type = CPU_TYPE_I386;
+ DPRINTF("cpu_type changed to 0x%x(i386)\n", data->cpu_type);
+#elif defined(TARGET_PPC)
+ data->cpu_type = CPU_TYPE_POWERPC;
+ DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type);
+#else
+# error target not supported
+#endif
+
+#if defined(TARGET_I386)
+ data->cpu_subtype = CPU_SUBTYPE_PENT;
+ DPRINTF("cpu_subtype changed to 0x%x(i386_pent)\n", data->cpu_subtype);
+#elif defined(TARGET_PPC)
+ data->cpu_subtype = CPU_SUBTYPE_POWERPC_750;
+ DPRINTF("cpu_subtype changed to 0x%x(ppc_all)\n", data->cpu_subtype);
+#else
+# error target not supported
+#endif
+ break;
+ }
+ case 202: /* host_page_size */
+ {
+ mig_reply_error_t *err = (mig_reply_error_t *)hdr;
+ uint32_t *pagesize = (uint32_t *)(err+1);
+
+ DPRINTF("pagesize = %d\n", *pagesize);
+ break;
+ }
+ default: break;
+ }
+
+ swap_mach_msg_header(hdr);
+
+ return ret;
+}
+
+long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8)
+{
+ extern uint32_t mach_reply_port();
+
+ long ret = 0;
+
+ arg1 = tswap32(arg1);
+ arg2 = tswap32(arg2);
+ arg3 = tswap32(arg3);
+ arg4 = tswap32(arg4);
+ arg5 = tswap32(arg5);
+ arg6 = tswap32(arg6);
+ arg7 = tswap32(arg7);
+ arg8 = tswap32(arg8);
+
+ DPRINTF("mach syscall %d : " , num);
+
+ switch(num) {
+ /* see xnu/osfmk/mach/syscall_sw.h */
+ case -26:
+ DPRINTF("mach_reply_port()\n");
+ ret = mach_reply_port();
+ break;
+ case -27:
+ DPRINTF("mach_thread_self()\n");
+ ret = mach_thread_self();
+ break;
+ case -28:
+ DPRINTF("mach_task_self()\n");
+ ret = mach_task_self();
+ break;
+ case -29:
+ DPRINTF("mach_host_self()\n");
+ ret = mach_host_self();
+ break;
+ case -31:
+ DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+
+ ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+
+ break;
+ case -36:
+ DPRINTF("semaphore_wait_trap(0x%x)\n", arg1);
+ extern int semaphore_wait_trap(int); // XXX: is there any header for that?
+ ret = semaphore_wait_trap(arg1);
+ break;
+ case -43:
+ DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
+ arg1, arg2, arg3, arg4, arg5);
+ ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5);
+ tswap32s((uint32_t*)arg3);
+ break;
+ case -89:
+ DPRINTF("mach_timebase_info(0x%x)\n", arg1);
+ struct mach_timebase_info info;
+ ret = mach_timebase_info(&info);
+ if(!is_error(ret))
+ {
+ struct mach_timebase_info *outInfo = (void*)arg1;
+ outInfo->numer = tswap32(info.numer);
+ outInfo->denom = tswap32(info.denom);
+ }
+ break;
+ case -90:
+ DPRINTF("mach_wait_until()\n");
+ extern int mach_wait_until(uint64_t); // XXX: is there any header for that?
+ ret = mach_wait_until(((uint64_t)arg2<<32) | (uint64_t)arg1);
+ break;
+ case -91:
+ DPRINTF("mk_timer_create()\n");
+ extern int mk_timer_create(); // XXX: is there any header for that?
+ ret = mk_timer_create();
+ break;
+ case -92:
+ DPRINTF("mk_timer_destroy()\n");
+ extern int mk_timer_destroy(int); // XXX: is there any header for that?
+ ret = mk_timer_destroy(arg1);
+ break;
+ case -93:
+ DPRINTF("mk_timer_create()\n");
+ extern int mk_timer_arm(int, uint64_t); // XXX: is there any header for that?
+ ret = mk_timer_arm(arg1, ((uint64_t)arg3<<32) | (uint64_t)arg2);
+ break;
+ case -94:
+ DPRINTF("mk_timer_cancel()\n");
+ extern int mk_timer_cancel(int, uint64_t *); // XXX: is there any header for that?
+ ret = mk_timer_cancel(arg1, (uint64_t *)arg2);
+ if((!is_error(ret)) && arg2)
+ tswap64s((uint64_t *)arg2);
+ break;
+ default:
+ gemu_log("qemu: Unsupported mach syscall: %d(0x%x)\n", num, num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(0);
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ thread type syscall handling
+*/
+long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8)
+{
+ extern uint32_t cthread_set_self(uint32_t);
+ extern uint32_t processor_facilities_used();
+ long ret = 0;
+
+ arg1 = tswap32(arg1);
+ arg2 = tswap32(arg2);
+ arg3 = tswap32(arg3);
+ arg4 = tswap32(arg4);
+ arg5 = tswap32(arg5);
+ arg6 = tswap32(arg6);
+ arg7 = tswap32(arg7);
+ arg8 = tswap32(arg8);
+
+ DPRINTF("thread syscall %d : " , num);
+
+ switch(num) {
+#ifdef TARGET_I386
+ case 0x3:
+#endif
+ case 0x7FF1: /* cthread_set_self */
+ DPRINTF("cthread_set_self(0x%x)\n", (unsigned int)arg1);
+ ret = cthread_set_self(arg1);
+#ifdef TARGET_I386
+ /* we need to update the LDT with the address of the thread */
+ write_dt((void *)(((CPUX86State *) cpu_env)->ldt.base + (4 * sizeof(uint64_t))), arg1, 1,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+ /* New i386 convention, %gs should be set to our this LDT entry */
+ cpu_x86_load_seg(cpu_env, R_GS, 0x27);
+ /* Old i386 convention, the kernel returns the selector for the cthread (pre-10.4.8?)*/
+ ret = 0x27;
+#endif
+ break;
+ case 0x7FF2: /* Called the super-fast pthread_self handler by the apple guys */
+ DPRINTF("pthread_self()\n");
+ ret = (uint32_t)pthread_self();
+ break;
+ case 0x7FF3:
+ DPRINTF("processor_facilities_used()\n");
+#ifdef __i386__
+ qerror("processor_facilities_used: not implemented!\n");
+#else
+ ret = (uint32_t)processor_facilities_used();
+#endif
+ break;
+ default:
+ gemu_log("qemu: Unsupported thread syscall: %d(0x%x)\n", num, num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(0);
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ ioctl handling
+*/
+static inline void byteswap_termios(struct termios *t)
+{
+ tswap32s((uint32_t*)&t->c_iflag);
+ tswap32s((uint32_t*)&t->c_oflag);
+ tswap32s((uint32_t*)&t->c_cflag);
+ tswap32s((uint32_t*)&t->c_lflag);
+ /* 20 (char) bytes then */
+ tswap32s((uint32_t*)&t->c_ispeed);
+ tswap32s((uint32_t*)&t->c_ospeed);
+}
+
+static inline void byteswap_winsize(struct winsize *w)
+{
+ tswap16s(&w->ws_row);
+ tswap16s(&w->ws_col);
+ tswap16s(&w->ws_xpixel);
+ tswap16s(&w->ws_ypixel);
+}
+
+#define STRUCT(name, list...) STRUCT_ ## name,
+#define STRUCT_SPECIAL(name) STRUCT_ ## name,
+enum {
+#include "ioctls_types.h"
+};
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL };
+#define STRUCT_SPECIAL(name)
+#include "ioctls_types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+typedef struct IOCTLEntry {
+ unsigned int target_cmd;
+ unsigned int host_cmd;
+ const char *name;
+ int access;
+ const argtype arg_type[5];
+} IOCTLEntry;
+
+#define IOC_R 0x0001
+#define IOC_W 0x0002
+#define IOC_RW (IOC_R | IOC_W)
+
+#define MAX_STRUCT_SIZE 4096
+
+IOCTLEntry ioctl_entries[] = {
+#define IOCTL(cmd, access, types...) \
+ { cmd, cmd, #cmd, access, { types } },
+#include "ioctls.h"
+ { 0, 0, },
+};
+
+/* ??? Implement proper locking for ioctls. */
+static long do_ioctl(long fd, long cmd, long arg)
+{
+ const IOCTLEntry *ie;
+ const argtype *arg_type;
+ int ret;
+ uint8_t buf_temp[MAX_STRUCT_SIZE];
+ int target_size;
+ void *argptr;
+
+ ie = ioctl_entries;
+ for(;;) {
+ if (ie->target_cmd == 0) {
+ gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd);
+ return -ENOSYS;
+ }
+ if (ie->target_cmd == cmd)
+ break;
+ ie++;
+ }
+ arg_type = ie->arg_type;
+#if defined(DEBUG)
+ gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name);
+#endif
+ switch(arg_type[0]) {
+ case TYPE_NULL:
+ /* no argument */
+ ret = get_errno(ioctl(fd, ie->host_cmd));
+ break;
+ case TYPE_PTRVOID:
+ case TYPE_INT:
+ /* int argment */
+ ret = get_errno(ioctl(fd, ie->host_cmd, arg));
+ break;
+ case TYPE_PTR:
+ arg_type++;
+ target_size = thunk_type_size(arg_type, 0);
+ switch(ie->access) {
+ case IOC_R:
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ if (!is_error(ret)) {
+ argptr = lock_user(arg, target_size, 0);
+ thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+ unlock_user(argptr, arg, target_size);
+ }
+ break;
+ case IOC_W:
+ argptr = lock_user(arg, target_size, 1);
+ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+ unlock_user(argptr, arg, 0);
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ break;
+ default:
+ case IOC_RW:
+ argptr = lock_user(arg, target_size, 1);
+ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+ unlock_user(argptr, arg, 0);
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ if (!is_error(ret)) {
+ argptr = lock_user(arg, target_size, 0);
+ thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+ unlock_user(argptr, arg, target_size);
+ }
+ break;
+ }
+ break;
+ default:
+ gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]);
+ ret = -ENOSYS;
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ Unix syscall handling
+*/
+
+static inline void byteswap_attrlist(struct attrlist *a)
+{
+ tswap16s(&a->bitmapcount);
+ tswap16s(&a->reserved);
+ tswap32s(&a->commonattr);
+ tswap32s(&a->volattr);
+ tswap32s(&a->dirattr);
+ tswap32s(&a->fileattr);
+ tswap32s(&a->forkattr);
+}
+
+struct attrbuf_header {
+ unsigned long length;
+};
+
+static inline void byteswap_attrbuf(struct attrbuf_header *attrbuf, struct attrlist *attrlist)
+{
+ DPRINTF("attrBuf.lenght %lx\n", attrbuf->length);
+}
+
+static inline void byteswap_statfs(struct statfs *s)
+{
+ tswap16s((uint16_t*)&s->f_otype);
+ tswap16s((uint16_t*)&s->f_oflags);
+ tswap32s((uint32_t*)&s->f_bsize);
+ tswap32s((uint32_t*)&s->f_iosize);
+ tswap32s((uint32_t*)&s->f_blocks);
+ tswap32s((uint32_t*)&s->f_bfree);
+ tswap32s((uint32_t*)&s->f_bavail);
+ tswap32s((uint32_t*)&s->f_files);
+ tswap32s((uint32_t*)&s->f_ffree);
+ tswap32s((uint32_t*)&s->f_fsid.val[0]);
+ tswap32s((uint32_t*)&s->f_fsid.val[1]);
+ tswap16s((uint16_t*)&s->f_reserved1);
+ tswap16s((uint16_t*)&s->f_type);
+ tswap32s((uint32_t*)&s->f_flags);
+}
+
+static inline void byteswap_stat(struct stat *s)
+{
+ tswap32s((uint32_t*)&s->st_dev);
+ tswap32s(&s->st_ino);
+ tswap16s(&s->st_mode);
+ tswap16s(&s->st_nlink);
+ tswap32s(&s->st_uid);
+ tswap32s(&s->st_gid);
+ tswap32s((uint32_t*)&s->st_rdev);
+ tswap32s((uint32_t*)&s->st_atimespec.tv_sec);
+ tswap32s((uint32_t*)&s->st_atimespec.tv_nsec);
+ tswap32s((uint32_t*)&s->st_mtimespec.tv_sec);
+ tswap32s((uint32_t*)&s->st_mtimespec.tv_nsec);
+ tswap32s((uint32_t*)&s->st_ctimespec.tv_sec);
+ tswap32s((uint32_t*)&s->st_ctimespec.tv_nsec);
+ tswap64s((uint64_t*)&s->st_size);
+ tswap64s((uint64_t*)&s->st_blocks);
+ tswap32s((uint32_t*)&s->st_blksize);
+ tswap32s(&s->st_flags);
+ tswap32s(&s->st_gen);
+}
+
+static inline void byteswap_dirents(struct dirent *d, int bytes)
+{
+ char *b;
+ for( b = (char*)d; (int)b < (int)d+bytes; )
+ {
+ unsigned short s = ((struct dirent *)b)->d_reclen;
+ tswap32s(&((struct dirent *)b)->d_ino);
+ tswap16s(&((struct dirent *)b)->d_reclen);
+ if(s<=0)
+ break;
+ b += s;
+ }
+}
+
+static inline void byteswap_iovec(struct iovec *v, int n)
+{
+ int i;
+ for(i = 0; i < n; i++)
+ {
+ tswap32s((uint32_t*)&v[i].iov_base);
+ tswap32s((uint32_t*)&v[i].iov_len);
+ }
+}
+
+static inline void byteswap_timeval(struct timeval *t)
+{
+ tswap32s((uint32_t*)&t->tv_sec);
+ tswap32s((uint32_t*)&t->tv_usec);
+}
+
+long do_unix_syscall_indirect(void *cpu_env, int num);
+long do_sync();
+long do_exit(uint32_t arg1);
+long do_getlogin(char *out, uint32_t size);
+long do_open(char * arg1, uint32_t arg2, uint32_t arg3);
+long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3);
+long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3);
+long do_execve(char* arg1, char ** arg2, char ** arg3);
+long do_getgroups(uint32_t arg1, gid_t * arg2);
+long do_gettimeofday(struct timeval * arg1, void * arg2);
+long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3);
+long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3);
+long do_utimes(char * arg1, struct timeval * arg2);
+long do_futimes(uint32_t arg1, struct timeval * arg2);
+long do_statfs(char * arg1, struct statfs * arg2);
+long do_fstatfs(uint32_t arg1, struct statfs * arg2);
+long do_stat(char * arg1, struct stat * arg2);
+long do_fstat(uint32_t arg1, struct stat * arg2);
+long do_lstat(char * arg1, struct stat * arg2);
+long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4);
+long do_lseek(void *cpu_env, int num);
+long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6);
+long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5);
+long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8);
+
+long no_syscall(void *cpu_env, int num);
+
+long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4)
+{
+ //DPRINTF("0x%x, 0x%x, 0x%x, 0x%llx\n", arg1, arg2, arg3, arg4);
+ long ret = (pread(arg1, arg2, arg3, arg4));
+ DPRINTF("0x%x\n", *(int*)arg2);
+ return ret;
+}
+long unimpl_unix_syscall(void *cpu_env, int num);
+
+typedef long (*syscall_function_t)(void *cpu_env, int num);
+
+
+/* define a table that will handle the syscall number->function association */
+#define VOID void
+#define INT (uint32_t)get_int_arg(&i, cpu_env)
+#define INT64 (uint64_t)get_int64_arg(&i, cpu_env)
+#define UINT (unsigned int)INT
+#define PTR (void*)INT
+
+#define SIZE INT
+#define OFFSET INT64
+
+#define WRAPPER_CALL_DIRECT_0(function, args) long __qemu_##function(void *cpu_env) { return (long)function(); }
+#define WRAPPER_CALL_DIRECT_1(function, _arg1) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; return (long)function(arg1); }
+#define WRAPPER_CALL_DIRECT_2(function, _arg1, _arg2) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; return (long)function(arg1, arg2); }
+#define WRAPPER_CALL_DIRECT_3(function, _arg1, _arg2, _arg3) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; return (long)function(arg1, arg2, arg3); }
+#define WRAPPER_CALL_DIRECT_4(function, _arg1, _arg2, _arg3, _arg4) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; return (long)function(arg1, arg2, arg3, arg4); }
+#define WRAPPER_CALL_DIRECT_5(function, _arg1, _arg2, _arg3, _arg4, _arg5) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; return (long)function(arg1, arg2, arg3, arg4, arg5); }
+#define WRAPPER_CALL_DIRECT_6(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6); }
+#define WRAPPER_CALL_DIRECT_7(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7); }
+#define WRAPPER_CALL_DIRECT_8(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; typeof(_arg8) arg8 = _arg8; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); }
+#define WRAPPER_CALL_DIRECT(function, nargs, args...) WRAPPER_CALL_DIRECT_##nargs(function, args)
+#define WRAPPER_CALL_NOERRNO(function, nargs, args...) WRAPPER_CALL_DIRECT(function, nargs, args)
+#define WRAPPER_CALL_INDIRECT(function, nargs, args...)
+#define ENTRY(name, number, function, nargs, call_type, args...) WRAPPER_##call_type(function, nargs, args)
+
+#include "syscalls.h"
+
+#undef ENTRY
+#undef WRAPPER_CALL_DIRECT
+#undef WRAPPER_CALL_NOERRNO
+#undef WRAPPER_CALL_INDIRECT
+#undef OFFSET
+#undef SIZE
+#undef INT
+#undef PTR
+#undef INT64
+
+#define _ENTRY(name, number, function, nargs, call_type) [number] = {\
+ name, \
+ number, \
+ (syscall_function_t)function, \
+ nargs, \
+ call_type \
+ },
+
+#define ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, __qemu_##function, nargs, call_type)
+#define ENTRY_CALL_NOERRNO(name, number, function, nargs, call_type) ENTRY_CALL_DIRECT(name, number, function, nargs, call_type)
+#define ENTRY_CALL_INDIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, function, nargs, call_type)
+#define ENTRY(name, number, function, nargs, call_type, args...) ENTRY_##call_type(name, number, function, nargs, call_type)
+
+#define CALL_DIRECT 1
+#define CALL_INDIRECT 2
+#define CALL_NOERRNO (CALL_DIRECT | 4 /* = 5 */)
+
+struct unix_syscall {
+ char * name;
+ int number;
+ syscall_function_t function;
+ int nargs;
+ int call_type;
+} unix_syscall_table[SYS_MAXSYSCALL] = {
+#include "syscalls.h"
+};
+
+#undef ENTRY
+#undef _ENTRY
+#undef ENTRY_CALL_DIRECT
+#undef ENTRY_CALL_INDIRECT
+#undef ENTRY_CALL_NOERRNO
+
+/* Actual syscalls implementation */
+
+long do_unix_syscall_indirect(void *cpu_env, int num)
+{
+ long ret;
+ int new_num;
+ int i = 0;
+
+ new_num = get_int_arg(&i, cpu_env);
+#ifdef TARGET_I386
+ ((CPUX86State*)cpu_env)->regs[R_ESP] += 4;
+ /* XXX: not necessary */
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = new_num;
+#elif TARGET_PPC
+ {
+ int i;
+ uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr;
+ for(i = 3; i < 11; i++)
+ *regs[i] = *regs[i+1];
+ /* XXX: not necessary */
+ *regs[0] = new_num;
+ }
+#endif
+ ret = do_unix_syscall(cpu_env, new_num);
+#ifdef TARGET_I386
+ ((CPUX86State*)cpu_env)->regs[R_ESP] -= 4;
+ /* XXX: not necessary */
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = num;
+#elif TARGET_PPC
+ {
+ int i;
+ /* XXX: not really needed those regs are volatile accross calls */
+ uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr;
+ for(i = 11; i > 3; i--)
+ *regs[i] = *regs[i-1];
+ regs[3] = new_num;
+ *regs[0] = num;
+ }
+#endif
+ return ret;
+}
+
+long do_exit(uint32_t arg1)
+{
+ exit(arg1);
+ /* not reached */
+ return -1;
+}
+
+long do_sync()
+{
+ sync();
+ return 0;
+}
+
+long do_getlogin(char *out, uint32_t size)
+{
+ char *login = getlogin();
+ if(!login)
+ return -1;
+ memcpy(out, login, size);
+ return 0;
+}
+long do_open(char * arg1, uint32_t arg2, uint32_t arg3)
+{
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("open(%s, 0x%x, 0x%x)\n", arg1, arg2, arg3);
+ return get_errno(open(arg1, arg2, arg3));
+}
+
+long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3)
+{
+ long ret;
+ DPRINTF("getfsstat(%p, 0x%x, 0x%x)\n", arg1, arg2, arg3);
+ ret = get_errno(getfsstat(arg1, arg2, arg3));
+ if((!is_error(ret)) && arg1)
+ byteswap_statfs(arg1);
+ return ret;
+}
+
+long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3)
+{
+ long ret;
+ DPRINTF("sigprocmask(%d, %p, %p)\n", arg1, arg2, arg3);
+ gemu_log("XXX: sigprocmask not tested (%d, %p, %p)\n", arg1, arg2, arg3);
+ if(arg2)
+ tswap32s(arg2);
+ ret = get_errno(sigprocmask(arg1, (void *)arg2, (void *)arg3));
+ if((!is_error(ret)) && arg3)
+ tswap32s(arg3);
+ if(arg2)
+ tswap32s(arg2);
+ return ret;
+}
+
+long do_execve(char* arg1, char ** arg2, char ** arg3)
+{
+ long ret;
+ char **argv = arg2;
+ char **envp = arg3;
+ int argc;
+ int envc;
+
+ /* XXX: don't let the %s stay in here */
+ DPRINTF("execve(%s, %p, %p)\n", arg1, arg2, arg3);
+
+ for(argc = 0; argv[argc]; argc++);
+ for(envc = 0; envp[envc]; envc++);
+
+ argv = (char**)malloc(sizeof(char*)*argc);
+ envp = (char**)malloc(sizeof(char*)*envc);
+
+ for(; argc >= 0; argc--)
+ argv[argc] = (char*)tswap32((uint32_t)(arg2)[argc]);
+
+ for(; envc >= 0; envc--)
+ envp[envc] = (char*)tswap32((uint32_t)(arg3)[envc]);
+
+ ret = get_errno(execve(arg1, argv, envp));
+ free(argv);
+ free(envp);
+ return ret;
+}
+
+long do_getgroups(uint32_t arg1, gid_t * arg2)
+{
+ long ret;
+ int i;
+ DPRINTF("getgroups(0x%x, %p)\n", arg1, arg2);
+ ret = get_errno(getgroups(arg1, arg2));
+ if(ret > 0)
+ for(i = 0; i < arg1; i++)
+ tswap32s(&arg2[i]);
+ return ret;
+}
+
+long do_gettimeofday(struct timeval * arg1, void * arg2)
+{
+ long ret;
+ DPRINTF("gettimeofday(%p, %p)\n",
+ arg1, arg2);
+ ret = get_errno(gettimeofday(arg1, arg2));
+ if(!is_error(ret))
+ {
+ /* timezone no longer used according to the manpage, so don't bother with it */
+ byteswap_timeval(arg1);
+ }
+ return ret;
+}
+
+long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3)
+{
+ long ret;
+ DPRINTF("readv(0x%x, %p, 0x%x)\n", arg1, arg2, arg3);
+ if(arg2)
+ byteswap_iovec(arg2, arg3);
+ ret = get_errno(readv(arg1, arg2, arg3));
+ if((!is_error(ret)) && arg2)
+ byteswap_iovec(arg2, arg3);
+ return ret;
+}
+
+long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3)
+{
+ long ret;
+ DPRINTF("writev(0x%x, %p, 0x%x)\n", arg1, arg2, arg3);
+ if(arg2)
+ byteswap_iovec(arg2, arg3);
+ ret = get_errno(writev(arg1, arg2, arg3));
+ if((!is_error(ret)) && arg2)
+ byteswap_iovec(arg2, arg3);
+ return ret;
+}
+
+long do_utimes(char * arg1, struct timeval * arg2)
+{
+ DPRINTF("utimes(%p, %p)\n", arg1, arg2);
+ if(arg2)
+ {
+ byteswap_timeval(arg2);
+ byteswap_timeval(arg2+1);
+ }
+ return get_errno(utimes(arg1, arg2));
+}
+
+long do_futimes(uint32_t arg1, struct timeval * arg2)
+{
+ DPRINTF("futimes(0x%x, %p)\n", arg1, arg2);
+ if(arg2)
+ {
+ byteswap_timeval(arg2);
+ byteswap_timeval(arg2+1);
+ }
+ return get_errno(futimes(arg1, arg2));
+}
+
+long do_statfs(char * arg1, struct statfs * arg2)
+{
+ long ret;
+ DPRINTF("statfs(%p, %p)\n", arg1, arg2);
+ ret = get_errno(statfs(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_statfs(arg2);
+ return ret;
+}
+
+long do_fstatfs(uint32_t arg1, struct statfs* arg2)
+{
+ long ret;
+ DPRINTF("fstatfs(0x%x, %p)\n",
+ arg1, arg2);
+ ret = get_errno(fstatfs(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_statfs(arg2);
+
+ return ret;
+}
+
+long do_stat(char * arg1, struct stat * arg2)
+{
+ long ret;
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("stat(%s, %p)\n", arg1, arg2);
+ ret = get_errno(stat(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_stat(arg2);
+ return ret;
+}
+
+long do_fstat(uint32_t arg1, struct stat * arg2)
+{
+ long ret;
+ DPRINTF("fstat(0x%x, %p)\n", arg1, arg2);
+ ret = get_errno(fstat(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_stat(arg2);
+ return ret;
+}
+
+long do_lstat(char * arg1, struct stat * arg2)
+{
+ long ret;
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("lstat(%s, %p)\n", (const char *)arg1, arg2);
+ ret = get_errno(lstat(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_stat(arg2);
+ return ret;
+}
+
+long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4)
+{
+ long ret;
+ DPRINTF("getdirentries(0x%x, %p, 0x%x, %p)\n", arg1, arg2, arg3, arg4);
+ if(arg4)
+ tswap32s((uint32_t *)arg4);
+ ret = get_errno(getdirentries(arg1, arg2, arg3, arg4));
+ if(arg4)
+ tswap32s((uint32_t *)arg4);
+ if(!is_error(ret))
+ byteswap_dirents(arg2, ret);
+ return ret;
+}
+
+long do_lseek(void *cpu_env, int num)
+{
+ long ret;
+ int i = 0;
+ uint32_t arg1 = get_int_arg(&i, cpu_env);
+ uint64_t offset = get_int64_arg(&i, cpu_env);
+ uint32_t arg3 = get_int_arg(&i, cpu_env);
+ uint64_t r = lseek(arg1, offset, arg3);
+#ifdef TARGET_I386
+ /* lowest word in eax, highest in edx */
+ ret = r & 0xffffffff; /* will be set to eax after do_unix_syscall exit */
+ ((CPUX86State *)cpu_env)->regs[R_EDX] = (uint32_t)((r >> 32) & 0xffffffff) ;
+#elif defined TARGET_PPC
+ ret = r & 0xffffffff; /* will be set to r3 after do_unix_syscall exit */
+ ((CPUPPCState *)cpu_env)->gpr[4] = (uint32_t)((r >> 32) & 0xffffffff) ;
+#else
+ qerror("64 bit ret value on your arch?");
+#endif
+ return get_errno(ret);
+}
+
+long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6)
+{
+ long ret = 0;
+ int i;
+ DPRINTF("sysctl(%p, 0x%x, %p, %p, %p, 0x%lx)\n",
+ arg1, arg2, arg3, arg4, arg5, arg6);
+ if(arg1) {
+ i = 0;
+ do { *((int *) arg1 + i) = tswap32(*((int *) arg1 + i)); } while (++i < arg2);
+ }
+
+ if(arg4)
+ *(int *) arg4 = tswap32(*(int *) arg4);
+ if(arg1)
+ ret = get_errno(sysctl((void *)arg1, arg2, (void *)arg3, (void *)arg4, (void *)arg5, arg6));
+
+ if ((ret == 0) && (arg2 == 2) && (*((int *) arg1) == 0) && (*((int *) arg1 + 1) == 3)) {
+ /* The output here is the new id - we need to swap it so it can be passed
+ back in (and then unswapped) */
+ int count = (*(int *) arg4) / sizeof(int);
+ i = 0;
+ do {
+ *((int *) arg3 + i) = tswap32(*((int *) arg3 + i));
+ } while (++i < count);
+ }
+ *(int *) arg4 = tswap32(*(int *) arg4);
+
+ return ret;
+}
+
+long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5)
+{
+ struct attrlist * attrlist = (void *)arg2;
+ long ret;
+
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+ qerror("SYS_getdirentriesattr unimplemented\n");
+#endif
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n",
+ (char *)arg1, arg2, arg3, arg4, arg5);
+
+ if(arg2) /* XXX: We should handle that in a copy especially
+ if the structure is not writable */
+ byteswap_attrlist(attrlist);
+
+ ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5));
+
+ if(!is_error(ret))
+ {
+ byteswap_attrbuf((void *)arg3, attrlist);
+ byteswap_attrlist(attrlist);
+ }
+ return ret;
+}
+
+long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8)
+{
+ DPRINTF("getdirentriesattr(0x%x, %p, %p, 0x%lx, %p, %p, %p, 0x%x)\n",
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+ qerror("SYS_getdirentriesattr unimplemented\n");
+#endif
+
+ return get_errno(getdirentriesattr( arg1, (struct attrlist * )arg2, (void *)arg3, arg4,
+ (unsigned long *)arg5, (unsigned long *)arg6,
+ (unsigned long *)arg7, arg8));
+}
+
+
+long no_syscall(void *cpu_env, int num)
+{
+ /* XXX: We should probably fordward it to the host kernel */
+ qerror("no unix syscall %d\n", num);
+ /* not reached */
+ return -1;
+}
+
+long unimpl_unix_syscall(void *cpu_env, int num)
+{
+ if( (num < 0) || (num > SYS_MAXSYSCALL-1) )
+ qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1);
+
+ gemu_log("qemu: Unsupported unix syscall %s %d\n", unix_syscall_table[num].name , num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(-1);
+}
+
+long do_unix_syscall(void *cpu_env, int num)
+{
+ long ret = 0;
+
+ DPRINTF("unix syscall %d: " , num);
+
+ if( (num < 0) || (num > SYS_MAXSYSCALL-1) )
+ qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1);
+
+ DPRINTF("%s [%s]", unix_syscall_table[num].name, unix_syscall_table[num].call_type & CALL_DIRECT ? "direct" : "indirect" );
+ ret = unix_syscall_table[num].function(cpu_env, num);
+
+ if(!(unix_syscall_table[num].call_type & CALL_NOERRNO))
+ ret = get_errno(ret);
+
+ DPRINTF("[returned 0x%x(%d)]\n", (int)ret, (int)ret);
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ syscall_init
+*/
+void syscall_init(void)
+{
+ /* Nothing yet */
+}
diff --git a/darwin-user/syscalls.h b/darwin-user/syscalls.h
new file mode 100644
index 000000000..d04295bed
--- /dev/null
+++ b/darwin-user/syscalls.h
@@ -0,0 +1,384 @@
+/* generated from xnu/bsd/kern/syscalls.master */
+
+ ENTRY("syscall", SYS_syscall, do_unix_syscall_indirect, 0, CALL_INDIRECT, VOID) /* 0 indirect syscall */
+ ENTRY("exit", SYS_exit, do_exit, 1, CALL_DIRECT, INT) /* 1 */
+ ENTRY("fork", SYS_fork, fork, 0, CALL_NOERRNO, VOID) /* 2 */
+ ENTRY("read", SYS_read, read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */
+ ENTRY("write", SYS_write, write, 3, CALL_DIRECT, INT, PTR, SIZE) /* 4 */
+ ENTRY("open", SYS_open, do_open, 3, CALL_DIRECT, PTR, INT, INT) /* 5 */
+ ENTRY("close", SYS_close, close, 1, CALL_DIRECT, INT) /* 6 */
+ ENTRY("wait4", SYS_wait4, wait4, 4, CALL_DIRECT, INT, PTR, INT, PTR) /* 7 */
+ ENTRY("", 8, no_syscall, 0, CALL_INDIRECT, VOID) /* 8 old creat */
+ ENTRY("link", SYS_link, link, 2, CALL_DIRECT, PTR, PTR) /* 9 */
+ ENTRY("unlink", SYS_unlink, unlink, 1, CALL_DIRECT, PTR) /* 10 */
+ ENTRY("", 11, no_syscall, 0, CALL_INDIRECT, VOID) /* 11 old execv */
+ ENTRY("chdir", SYS_chdir, chdir, 1, CALL_DIRECT, PTR) /* 12 */
+ ENTRY("fchdir", SYS_fchdir, fchdir, 1, CALL_DIRECT, INT) /* 13 */
+ ENTRY("mknod", SYS_mknod, mknod, 3, CALL_DIRECT, PTR, INT, INT) /* 14 */
+ ENTRY("chmod", SYS_chmod, chmod, 2, CALL_DIRECT, PTR, INT) /* 15 */
+ ENTRY("chown", SYS_chown, chown, 3, CALL_DIRECT, PTR, INT, INT) /* 16 */
+ ENTRY("obreak", SYS_obreak, no_syscall, 1, CALL_INDIRECT, VOID) /* 17 old break */
+ ENTRY("ogetfsstat", 18, unimpl_unix_syscall, 3, CALL_INDIRECT, PTR, INT, INT) /* 18 */
+ ENTRY("", 19, no_syscall, 0, CALL_INDIRECT, VOID) /* 19 old lseek */
+ ENTRY("getpid", SYS_getpid, getpid, 0, CALL_NOERRNO, VOID) /* 20 */
+ ENTRY("", 21, no_syscall, 0, CALL_INDIRECT, VOID) /* 21 old mount */
+ ENTRY("", 22, no_syscall, 0, CALL_INDIRECT, VOID) /* 22 old umount */
+ ENTRY("setuid", SYS_setuid, setuid, 1, CALL_DIRECT, INT) /* 23 */
+ ENTRY("getuid", SYS_getuid, getuid, 0, CALL_NOERRNO, VOID) /* 24 */
+ ENTRY("geteuid", SYS_geteuid, geteuid, 0, CALL_NOERRNO, VOID) /* 25 */
+ ENTRY("ptrace", SYS_ptrace, ptrace, 4, CALL_DIRECT, INT, INT, PTR, INT) /* 26 */
+ ENTRY("recvmsg", SYS_recvmsg, recvmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 27 */
+ ENTRY("sendmsg", SYS_sendmsg, sendmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 28 */
+ ENTRY("recvfrom", SYS_recvfrom, recvfrom, 6, CALL_DIRECT, INT, PTR, INT, INT, PTR, PTR) /* 29 */
+ ENTRY("accept", SYS_accept, accept, 3, CALL_DIRECT, INT, PTR, PTR) /* 30 */
+ ENTRY("getpeername", SYS_getpeername, getpeername, 3, CALL_DIRECT, INT, PTR, PTR) /* 31 */
+ ENTRY("getsockname", SYS_getsockname, getsockname, 3, CALL_DIRECT, INT, PTR, PTR) /* 32 */
+ ENTRY("access", SYS_access, access, 2, CALL_DIRECT, PTR, INT) /* 33 */
+ ENTRY("chflags", SYS_chflags, chflags, 2, CALL_DIRECT, PTR, INT) /* 34 */
+ ENTRY("fchflags", SYS_fchflags, fchflags, 2, CALL_DIRECT, INT, INT) /* 35 */
+ ENTRY("sync", SYS_sync, do_sync, 0, CALL_INDIRECT, VOID) /* 36 */
+ ENTRY("kill", SYS_kill, kill, 2, CALL_DIRECT, INT, INT) /* 37 */
+ ENTRY("", 38, no_syscall, 0, CALL_INDIRECT, VOID) /* 38 old stat */
+ ENTRY("getppid", SYS_getppid, getppid, 0, CALL_DIRECT, VOID) /* 39 */
+ ENTRY("", 40, no_syscall, 0, CALL_INDIRECT, VOID) /* 40 old lstat */
+ ENTRY("dup", SYS_dup, dup, 1, CALL_DIRECT, INT) /* 41 */
+ ENTRY("pipe", SYS_pipe, unimpl_unix_syscall, 0, CALL_INDIRECT, PTR) /* 42 */
+ ENTRY("getegid", SYS_getegid, getegid, 0, CALL_NOERRNO, VOID) /* 43 */
+ ENTRY("profil", SYS_profil, profil, 4, CALL_DIRECT, PTR, SIZE, INT, INT) /* 44 */
+ ENTRY("ktrace", SYS_ktrace, no_syscall, 4, CALL_INDIRECT, VOID) /* 45 */
+ ENTRY("sigaction", SYS_sigaction, do_sigaction, 3, CALL_DIRECT, INT, PTR, PTR) /* 46 */
+ ENTRY("getgid", SYS_getgid, getgid, 0, CALL_NOERRNO, VOID) /* 47 */
+ ENTRY("sigprocmask", SYS_sigprocmask, do_sigprocmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 48 */
+ ENTRY("getlogin", SYS_getlogin, do_getlogin, 2, CALL_DIRECT, PTR, UINT) /* 49 XXX */
+ ENTRY("setlogin", SYS_setlogin, setlogin, 1, CALL_DIRECT, PTR) /* 50 */
+ ENTRY("acct", SYS_acct, acct, 1, CALL_DIRECT, PTR) /* 51 */
+ ENTRY("sigpending", SYS_sigpending, sigpending, 1, CALL_DIRECT, PTR) /* 52 */
+ ENTRY("sigaltstack", SYS_sigaltstack, do_sigaltstack, 2, CALL_DIRECT, PTR, PTR) /* 53 */
+ ENTRY("ioctl", SYS_ioctl, do_ioctl, 3, CALL_DIRECT, INT, INT, INT) /* 54 */
+ ENTRY("reboot", SYS_reboot, unimpl_unix_syscall, 2, CALL_INDIRECT, INT, PTR) /* 55 */
+ ENTRY("revoke", SYS_revoke, revoke, 1, CALL_DIRECT, PTR) /* 56 */
+ ENTRY("symlink", SYS_symlink, symlink, 2, CALL_DIRECT, PTR, PTR) /* 57 */
+ ENTRY("readlink", SYS_readlink, readlink, 3, CALL_DIRECT, PTR, PTR, INT) /* 58 */
+ ENTRY("execve", SYS_execve, do_execve, 3, CALL_DIRECT, PTR, PTR, PTR) /* 59 */
+ ENTRY("umask", SYS_umask, umask, 1, CALL_DIRECT, INT) /* 60 */
+ ENTRY("chroot", SYS_chroot, chroot, 1, CALL_DIRECT, PTR) /* 61 */
+ ENTRY("", 62, no_syscall, 0, CALL_INDIRECT, VOID) /* 62 old fstat */
+ ENTRY("", 63, no_syscall, 0, CALL_INDIRECT, VOID) /* 63 used internally , reserved */
+ ENTRY("", 64, no_syscall, 0, CALL_INDIRECT, VOID) /* 64 old getpagesize */
+ ENTRY("msync", SYS_msync, target_msync, 3, CALL_DIRECT, UINT /*PTR*/, SIZE, INT) /* 65 */
+ ENTRY("vfork", SYS_vfork, vfork, 0, CALL_DIRECT, VOID) /* 66 */
+ ENTRY("", 67, no_syscall, 0, CALL_INDIRECT, VOID) /* 67 old vread */
+ ENTRY("", 68, no_syscall, 0, CALL_INDIRECT, VOID) /* 68 old vwrite */
+ ENTRY("sbrk", SYS_sbrk, sbrk, 1, CALL_DIRECT, INT) /* 69 */
+ ENTRY("sstk", SYS_sstk, no_syscall, 1, CALL_INDIRECT, VOID) /* 70 */
+ ENTRY("", 71, no_syscall, 0, CALL_INDIRECT, VOID) /* 71 old mmap */
+ ENTRY("ovadvise", SYS_ovadvise, no_syscall, 0, CALL_INDIRECT, VOID) /* 72 old vadvise */
+ ENTRY("munmap", SYS_munmap, target_munmap, 2, CALL_DIRECT, UINT /* PTR */, SIZE) /* 73 */
+ ENTRY("mprotect", SYS_mprotect, mprotect, 3, CALL_DIRECT, PTR, SIZE, INT) /* 74 */
+ ENTRY("madvise", SYS_madvise, madvise, 3, CALL_DIRECT, PTR, SIZE, INT) /* 75 */
+ ENTRY("", 76, no_syscall, 0, CALL_INDIRECT, VOID) /* 76 old vhangup */
+ ENTRY("", 77, no_syscall, 0, CALL_INDIRECT, VOID) /* 77 old vlimit */
+ ENTRY("mincore", SYS_mincore, mincore, 3, CALL_DIRECT, PTR, SIZE, PTR) /* 78 */
+ ENTRY("getgroups", SYS_getgroups, do_getgroups, 2, CALL_DIRECT, UINT, PTR) /* 79 */
+ ENTRY("setgroups", SYS_setgroups, setgroups, 2, CALL_DIRECT, UINT, PTR) /* 80 */
+ ENTRY("getpgrp", SYS_getpgrp, getpgrp, 0, CALL_DIRECT, VOID) /* 81 */
+ ENTRY("setpgid", SYS_setpgid, setpgid, 2, CALL_DIRECT, INT, INT) /* 82 */
+ ENTRY("setitimer", SYS_setitimer, setitimer, 3, CALL_DIRECT, INT, PTR, PTR) /* 83 */
+ ENTRY("", 84, no_syscall, 0, CALL_INDIRECT, VOID) /* 84 old wait */
+ ENTRY("swapon", SYS_swapon, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 85 */
+ ENTRY("getitimer", SYS_getitimer, getitimer, 2, CALL_DIRECT, INT, PTR) /* 86 */
+ ENTRY("", 87, no_syscall, 0, CALL_INDIRECT, VOID) /* 87 old gethostname */
+ ENTRY("", 88, no_syscall, 0, CALL_INDIRECT, VOID) /* 88 old sethostname */
+ ENTRY("getdtablesize", SYS_getdtablesize, getdtablesize, 0, CALL_DIRECT, VOID) /* 89 */
+ ENTRY("dup2", SYS_dup2, dup2, 2, CALL_DIRECT, INT, INT) /* 90 */
+ ENTRY("", 91, no_syscall, 0, CALL_INDIRECT, VOID) /* 91 old getdopt */
+ ENTRY("fcntl", SYS_fcntl, fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */
+ ENTRY("select", SYS_select, select, 5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR) /* 93 */
+ ENTRY("", 94, no_syscall, 0, CALL_INDIRECT, VOID) /* 94 old setdopt */
+ ENTRY("fsync", SYS_fsync, fsync, 1, CALL_DIRECT, INT) /* 95 */
+ ENTRY("setpriority", SYS_setpriority, setpriority, 3, CALL_DIRECT, INT, INT, INT) /* 96 */
+ ENTRY("socket", SYS_socket, socket, 3, CALL_DIRECT, INT, INT, INT) /* 97 */
+ ENTRY("connect", SYS_connect, connect, 3, CALL_DIRECT, INT, PTR, INT) /* 98 */
+ ENTRY("", 99, no_syscall, 0, CALL_INDIRECT, VOID) /* 99 old accept */
+ ENTRY("getpriority", SYS_getpriority, getpriority, 2, CALL_DIRECT, INT, INT) /* 100 */
+ ENTRY("", 101, no_syscall, 0, CALL_INDIRECT, VOID) /* 101 old send */
+ ENTRY("", 102, no_syscall, 0, CALL_INDIRECT, VOID) /* 102 old recv */
+ ENTRY("", 103, no_syscall, 0, CALL_INDIRECT, VOID) /* 103 old sigreturn */
+ ENTRY("bind", SYS_bind, bind, 3, CALL_DIRECT, INT, PTR, INT) /* 104 */
+ ENTRY("setsockopt", SYS_setsockopt, setsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, INT) /* 105 */
+ ENTRY("listen", SYS_listen, listen, 2, CALL_DIRECT, INT, INT) /* 106 */
+ ENTRY("", 107, no_syscall, 0, CALL_INDIRECT, VOID) /* 107 old vtimes */
+ ENTRY("", 108, no_syscall, 0, CALL_INDIRECT, VOID) /* 108 old sigvec */
+ ENTRY("", 109, no_syscall, 0, CALL_INDIRECT, VOID) /* 109 old sigblock */
+ ENTRY("", 110, no_syscall, 0, CALL_INDIRECT, VOID) /* 110 old sigsetmask */
+ ENTRY("sigsuspend", SYS_sigsuspend, unimpl_unix_syscall, 1, CALL_INDIRECT, INT) /* 111 */
+ ENTRY("", 112, no_syscall, 0, CALL_INDIRECT, VOID) /* 112 old sigstack */
+ ENTRY("", 113, no_syscall, 0, CALL_INDIRECT, VOID) /* 113 old recvmsg */
+ ENTRY("", 114, no_syscall, 0, CALL_INDIRECT, VOID) /* 114 old sendmsg */
+ ENTRY("", 115, no_syscall, 0, CALL_INDIRECT, VOID) /* 115 old vtrace */
+ ENTRY("gettimeofday", SYS_gettimeofday, do_gettimeofday, 2, CALL_DIRECT, PTR, PTR) /* 116 */
+ ENTRY("getrusage", SYS_getrusage, getrusage, 2, CALL_DIRECT, INT, PTR) /* 117 */
+ ENTRY("getsockopt", SYS_getsockopt, getsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, PTR) /* 118 */
+ ENTRY("", 119, no_syscall, 0, CALL_INDIRECT, VOID) /* 119 old resuba */
+ ENTRY("readv", SYS_readv, do_readv, 3, CALL_DIRECT, INT, PTR, UINT) /* 120 */
+ ENTRY("writev", SYS_writev, do_writev, 3, CALL_DIRECT, INT, PTR, UINT) /* 121 */
+ ENTRY("settimeofday", SYS_settimeofday, settimeofday, 2, CALL_DIRECT, PTR, PTR) /* 122 */
+ ENTRY("fchown", SYS_fchown, fchown, 3, CALL_DIRECT, INT, INT, INT) /* 123 */
+ ENTRY("fchmod", SYS_fchmod, fchmod, 2, CALL_DIRECT, INT, INT) /* 124 */
+ ENTRY("", 125, no_syscall, 0, CALL_INDIRECT, VOID) /* 125 old recvfrom */
+ ENTRY("", 126, no_syscall, 0, CALL_INDIRECT, VOID) /* 126 old setreuid */
+ ENTRY("", 127, no_syscall, 0, CALL_INDIRECT, VOID) /* 127 old setregid */
+ ENTRY("rename", SYS_rename, rename, 2, CALL_DIRECT, PTR, PTR) /* 128 */
+ ENTRY("", 129, no_syscall, 0, CALL_INDIRECT, VOID) /* 129 old truncate */
+ ENTRY("", 130, no_syscall, 0, CALL_INDIRECT, VOID) /* 130 old ftruncate */
+ ENTRY("flock", SYS_flock, flock, 2, CALL_DIRECT, INT, INT) /* 131 */
+ ENTRY("mkfifo", SYS_mkfifo, mkfifo, 2, CALL_DIRECT, PTR, INT) /* 132 */
+ ENTRY("sendto", SYS_sendto, sendto, 6, CALL_DIRECT, INT, PTR, SIZE, INT, PTR, INT) /* 133 */
+ ENTRY("shutdown", SYS_shutdown, shutdown, 2, CALL_DIRECT, INT, INT) /* 134 */
+ ENTRY("socketpair", SYS_socketpair, socketpair, 4, CALL_DIRECT, INT, INT, INT, PTR) /* 135 */
+ ENTRY("mkdir", SYS_mkdir, mkdir, 2, CALL_DIRECT, PTR, INT) /* 136 */
+ ENTRY("rmdir", SYS_rmdir, rmdir, 1, CALL_DIRECT, PTR) /* 137 */
+ ENTRY("utimes", SYS_utimes, do_utimes, 2, CALL_DIRECT, PTR, PTR) /* 138 */
+ ENTRY("futimes", SYS_futimes, do_futimes, 2, CALL_DIRECT, INT, PTR) /* 139 */
+ ENTRY("adjtime", SYS_adjtime, adjtime, 2, CALL_DIRECT, PTR, PTR) /* 140 */
+ ENTRY("", 141, no_syscall, 0, CALL_INDIRECT, VOID) /* 141 old getpeername */
+ ENTRY("", 142, no_syscall, 0, CALL_INDIRECT, VOID) /* 142 old gethostid */
+ ENTRY("", 143, no_syscall, 0, CALL_INDIRECT, VOID) /* 143 old sethostid */
+ ENTRY("", 144, no_syscall, 0, CALL_INDIRECT, VOID) /* 144 old getrlimit */
+ ENTRY("", 145, no_syscall, 0, CALL_INDIRECT, VOID) /* 145 old setrlimit */
+ ENTRY("", 146, no_syscall, 0, CALL_INDIRECT, VOID) /* 146 old killpg */
+ ENTRY("setsid", SYS_setsid, setsid, 0, CALL_DIRECT, VOID) /* 147 */
+ ENTRY("", 148, no_syscall, 0, CALL_INDIRECT, VOID) /* 148 old setquota */
+ ENTRY("", 149, no_syscall, 0, CALL_INDIRECT, VOID) /* 149 old qquota */
+ ENTRY("", 150, no_syscall, 0, CALL_INDIRECT, VOID) /* 150 old getsockname */
+ ENTRY("getpgid", SYS_getpgid, getpgid, 1, CALL_DIRECT, INT) /* 151 */
+ ENTRY("setprivexec", SYS_setprivexec, no_syscall, 1, CALL_INDIRECT, VOID) /* 152 */
+ ENTRY("pread", SYS_pread, do_pread, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 153 */
+ ENTRY("pwrite", SYS_pwrite, pwrite, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 154 */
+#ifdef SYS_nfssvc
+ ENTRY("nfssvc", SYS_nfssvc, nfssvc, 2, CALL_DIRECT, INT, PTR) /* 155 */
+#else
+ ENTRY("nfssvc", 155, no_syscall, 2, CALL_INDIRECT, VOID) /* 155 */
+#endif
+ ENTRY("", 155, no_syscall, 0, CALL_INDIRECT, VOID) /* 155 */
+ ENTRY("", 156, no_syscall, 0, CALL_INDIRECT, VOID) /* 156 old getdirentries */
+ ENTRY("statfs", SYS_statfs, do_statfs, 2, CALL_DIRECT, PTR, PTR) /* 157 */
+ ENTRY("fstatfs", SYS_fstatfs, do_fstatfs, 2, CALL_DIRECT, INT, PTR) /* 158 */
+ ENTRY("unmount", SYS_unmount, unmount, 2, CALL_DIRECT, PTR, INT) /* 159 */
+ ENTRY("", 160, no_syscall, 0, CALL_INDIRECT, VOID) /* 160 old async_daemon */
+ ENTRY("", 161, no_syscall, 0, CALL_INDIRECT, VOID) /* 161 */
+ ENTRY("", 162, no_syscall, 0, CALL_INDIRECT, VOID) /* 162 old getdomainname */
+ ENTRY("", 163, no_syscall, 0, CALL_INDIRECT, VOID) /* 163 old setdomainname */
+ ENTRY("", 164, no_syscall, 0, CALL_INDIRECT, VOID) /* 164 */
+ ENTRY("quotactl", SYS_quotactl, no_syscall, 4, CALL_INDIRECT, VOID) /* 165 */
+ ENTRY("", 166, no_syscall, 0, CALL_INDIRECT, VOID) /* 166 old exportfs */
+ ENTRY("mount", SYS_mount, mount, 4, CALL_DIRECT, PTR, PTR, INT, PTR) /* 167 */
+ ENTRY("", 168, no_syscall, 0, CALL_INDIRECT, VOID) /* 168 old ustat */
+ ENTRY("", 169, no_syscall, 0, CALL_INDIRECT, VOID) /* 169 */
+ ENTRY("table", SYS_table, no_syscall, 0, CALL_INDIRECT, VOID) /* 170 old table */
+ ENTRY("", 171, no_syscall, 0, CALL_INDIRECT, VOID) /* 171 old wait3 */
+ ENTRY("", 172, no_syscall, 0, CALL_INDIRECT, VOID) /* 172 old rpause */
+ ENTRY("waitid", SYS_waitid, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 173 */
+ ENTRY("", 174, no_syscall, 0, CALL_INDIRECT, VOID) /* 174 old getdents */
+ ENTRY("", 175, no_syscall, 0, CALL_INDIRECT, VOID) /* 175 old gc_control */
+ ENTRY("add_profil", SYS_add_profil, add_profil, 4, CALL_DIRECT, PTR, SIZE, UINT, UINT) /* 176 */
+ ENTRY("", 177, no_syscall, 0, CALL_INDIRECT, VOID) /* 177 */
+ ENTRY("", 178, no_syscall, 0, CALL_INDIRECT, VOID) /* 178 */
+ ENTRY("", 179, no_syscall, 0, CALL_INDIRECT, VOID) /* 179 */
+ ENTRY("kdebug_trace", SYS_kdebug_trace, no_syscall, 6, CALL_INDIRECT, VOID) /* 180 */
+ ENTRY("setgid", SYS_setgid, setgid, 1, CALL_DIRECT, INT) /* 181 */
+ ENTRY("setegid", SYS_setegid, setegid, 1, CALL_DIRECT, INT) /* 182 */
+ ENTRY("seteuid", SYS_seteuid, seteuid, 1, CALL_DIRECT, INT) /* 183 */
+ ENTRY("sigreturn", SYS_sigreturn, do_sigreturn, 2, CALL_INDIRECT, PTR, INT) /* 184 */
+ ENTRY("chud", SYS_chud, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 185 */
+ ENTRY("", 186, no_syscall, 0, CALL_INDIRECT, VOID) /* 186 */
+ ENTRY("", 187, no_syscall, 0, CALL_INDIRECT, VOID) /* 187 */
+ ENTRY("stat", SYS_stat, do_stat, 2, CALL_DIRECT, PTR, PTR) /* 188 */
+ ENTRY("fstat", SYS_fstat, do_fstat, 2, CALL_DIRECT, INT, PTR) /* 189 */
+ ENTRY("lstat", SYS_lstat, do_lstat, 2, CALL_DIRECT, PTR, PTR) /* 190 */
+ ENTRY("pathconf", SYS_pathconf, pathconf, 2, CALL_DIRECT, PTR, INT) /* 191 */
+ ENTRY("fpathconf", SYS_fpathconf, fpathconf, 2, CALL_DIRECT, INT, INT) /* 192 */
+ ENTRY("getfsstat", SYS_getfsstat, do_getfsstat, 3, CALL_DIRECT, PTR, INT, INT) /* 193 */
+ ENTRY("", 193, no_syscall, 0, CALL_INDIRECT, VOID) /* 193 */
+ ENTRY("getrlimit", SYS_getrlimit, getrlimit, 2, CALL_DIRECT, UINT, PTR) /* 194 */
+ ENTRY("setrlimit", SYS_setrlimit, setrlimit, 2, CALL_DIRECT, UINT, PTR) /* 195 */
+ ENTRY("getdirentries", SYS_getdirentries, do_getdirentries, 4, CALL_DIRECT, INT, PTR, UINT, PTR) /* 196 */
+ ENTRY("mmap", SYS_mmap, target_mmap, 6, CALL_DIRECT, UINT /*PTR*/, SIZE, INT, INT, INT, OFFSET) /* 197 */
+ ENTRY("", 198, no_syscall, 0, CALL_INDIRECT, VOID) /* 198 __syscall */
+ ENTRY("lseek", SYS_lseek, do_lseek, 3, CALL_INDIRECT, INT, OFFSET, INT) /* 199 */
+ ENTRY("truncate", SYS_truncate, truncate, 2, CALL_DIRECT, PTR, OFFSET) /* 200 */
+ ENTRY("ftruncate", SYS_ftruncate, ftruncate, 2, CALL_DIRECT, INT, OFFSET) /* 201 */
+ ENTRY("__sysctl", SYS___sysctl, do___sysctl, 6, CALL_DIRECT, PTR, INT, PTR, PTR, PTR, SIZE) /* 202 */
+ ENTRY("mlock", SYS_mlock, mlock, 2, CALL_DIRECT, PTR, SIZE) /* 203 */
+ ENTRY("munlock", SYS_munlock, munlock, 2, CALL_DIRECT, PTR, SIZE) /* 204 */
+ ENTRY("undelete", SYS_undelete, undelete, 1, CALL_DIRECT, PTR) /* 205 */
+ ENTRY("ATsocket", SYS_ATsocket, no_syscall, 1, CALL_INDIRECT, VOID) /* 206 */
+ ENTRY("ATgetmsg", SYS_ATgetmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 207 */
+ ENTRY("ATputmsg", SYS_ATputmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 208 */
+ ENTRY("ATPsndreq", SYS_ATPsndreq, no_syscall, 4, CALL_INDIRECT, VOID) /* 209 */
+ ENTRY("ATPsndrsp", SYS_ATPsndrsp, no_syscall, 4, CALL_INDIRECT, VOID) /* 210 */
+ ENTRY("ATPgetreq", SYS_ATPgetreq, no_syscall, 3, CALL_INDIRECT, VOID) /* 211 */
+ ENTRY("ATPgetrsp", SYS_ATPgetrsp, no_syscall, 2, CALL_INDIRECT, VOID) /* 212 */
+ ENTRY("", 213, no_syscall, 0, CALL_INDIRECT, VOID) /* 213 Reserved for AppleTalk */
+ ENTRY("kqueue_from_portset_np", SYS_kqueue_from_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 214 */
+ ENTRY("kqueue_portset_np", SYS_kqueue_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 215 */
+ ENTRY("mkcomplex", SYS_mkcomplex, no_syscall, 3, CALL_INDIRECT, VOID) /* 216 soon to be obsolete */
+ ENTRY("statv", SYS_statv, no_syscall, 2, CALL_INDIRECT, VOID) /* 217 soon to be obsolete */
+ ENTRY("lstatv", SYS_lstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 218 soon to be obsolete */
+ ENTRY("fstatv", SYS_fstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 219 soon to be obsolete */
+ ENTRY("getattrlist", SYS_getattrlist, do_getattrlist, 5, CALL_DIRECT, PTR, PTR, PTR, SIZE, UINT) /* 220 */
+ ENTRY("setattrlist", SYS_setattrlist, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 221 */
+ ENTRY("getdirentriesattr", SYS_getdirentriesattr, do_getdirentriesattr, 8, CALL_DIRECT, INT, PTR, PTR, SIZE, PTR, PTR, PTR, UINT) /* 222 */
+ ENTRY("exchangedata", SYS_exchangedata, exchangedata, 3, CALL_DIRECT, PTR, PTR, UINT) /* 223 */
+ ENTRY("checkuseraccess", SYS_checkuseraccess, checkuseraccess, 6, CALL_DIRECT, PTR, INT, PTR, INT, INT, UINT) /* 224 */
+ ENTRY("", 224, no_syscall, 0, CALL_INDIRECT, VOID) /* 224 HFS checkuseraccess check access to a file */
+ ENTRY("searchfs", SYS_searchfs, searchfs, 6, CALL_DIRECT, PTR, PTR, PTR, UINT, UINT, PTR) /* 225 */
+ ENTRY("delete", SYS_delete, no_syscall, 1, CALL_INDIRECT, VOID) /* 226 private delete ( Carbon semantics ) */
+ ENTRY("copyfile", SYS_copyfile, no_syscall, 4, CALL_INDIRECT, VOID) /* 227 */
+ ENTRY("", 228, no_syscall, 0, CALL_INDIRECT, VOID) /* 228 */
+ ENTRY("", 229, no_syscall, 0, CALL_INDIRECT, VOID) /* 229 */
+ ENTRY("poll", SYS_poll, no_syscall, 3, CALL_INDIRECT, VOID) /* 230 */
+ ENTRY("watchevent", SYS_watchevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 231 */
+ ENTRY("waitevent", SYS_waitevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 232 */
+ ENTRY("modwatch", SYS_modwatch, no_syscall, 2, CALL_INDIRECT, VOID) /* 233 */
+ ENTRY("getxattr", SYS_getxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 234 */
+ ENTRY("fgetxattr", SYS_fgetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 235 */
+ ENTRY("setxattr", SYS_setxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 236 */
+ ENTRY("fsetxattr", SYS_fsetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 237 */
+ ENTRY("removexattr", SYS_removexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 238 */
+ ENTRY("fremovexattr", SYS_fremovexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 239 */
+ ENTRY("listxattr", SYS_listxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 240 */
+ ENTRY("flistxattr", SYS_flistxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 241 */
+ ENTRY("fsctl", SYS_fsctl, fsctl, 4, CALL_DIRECT, PTR, UINT, PTR, UINT) /* 242 */
+ ENTRY("initgroups", SYS_initgroups, unimpl_unix_syscall, 3, CALL_INDIRECT, UINT, PTR, INT) /* 243 */
+ ENTRY("", 244, no_syscall, 0, CALL_INDIRECT, VOID) /* 244 */
+ ENTRY("", 245, no_syscall, 0, CALL_INDIRECT, VOID) /* 245 */
+ ENTRY("", 246, no_syscall, 0, CALL_INDIRECT, VOID) /* 246 */
+#ifdef SYS_nfsclnt
+ ENTRY("nfsclnt", SYS_nfsclnt, nfsclnt, 2, CALL_DIRECT, INT, PTR) /* 247 */
+#else
+ ENTRY("nfsclnt", 247, no_syscall, 2, CALL_INDIRECT, VOID) /* 247 */
+#endif
+ ENTRY("", 247, no_syscall, 0, CALL_INDIRECT, VOID) /* 247 */
+ ENTRY("", 248, no_syscall, 0, CALL_INDIRECT, VOID) /* 248 */
+ ENTRY("", 249, no_syscall, 0, CALL_INDIRECT, VOID) /* 249 */
+ ENTRY("minherit", SYS_minherit, minherit, 3, CALL_DIRECT, PTR, INT, INT) /* 250 */
+ ENTRY("semsys", SYS_semsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 251 */
+ ENTRY("msgsys", SYS_msgsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 252 */
+ ENTRY("shmsys", SYS_shmsys, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 253 */
+ ENTRY("semctl", SYS_semctl, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 254 */
+ ENTRY("semget", SYS_semget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 255 */
+ ENTRY("semop", SYS_semop, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 256 */
+ ENTRY("", 257, no_syscall, 0, CALL_INDIRECT, VOID) /* 257 */
+ ENTRY("msgctl", SYS_msgctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 258 */
+ ENTRY("msgget", SYS_msgget, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 259 */
+ ENTRY("msgsnd", SYS_msgsnd, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 260 */
+ ENTRY("msgrcv", SYS_msgrcv, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 261 */
+ ENTRY("shmat", SYS_shmat, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 262 */
+ ENTRY("shmctl", SYS_shmctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 263 */
+ ENTRY("shmdt", SYS_shmdt, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 264 */
+ ENTRY("shmget", SYS_shmget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 265 */
+ ENTRY("shm_open", SYS_shm_open, shm_open, 3, CALL_DIRECT, PTR, INT, INT) /* 266 */
+ ENTRY("shm_unlink", SYS_shm_unlink, shm_unlink, 1, CALL_DIRECT, PTR) /* 267 */
+ ENTRY("sem_open", SYS_sem_open, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 268 */
+ ENTRY("sem_close", SYS_sem_close, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 269 */
+ ENTRY("sem_unlink", SYS_sem_unlink, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 270 */
+ ENTRY("sem_wait", SYS_sem_wait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 271 */
+ ENTRY("sem_trywait", SYS_sem_trywait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 272 */
+ ENTRY("sem_post", SYS_sem_post, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 273 */
+ ENTRY("sem_getvalue", SYS_sem_getvalue, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 274 */
+ ENTRY("sem_init", SYS_sem_init, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 275 */
+ ENTRY("sem_destroy", SYS_sem_destroy, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 276 */
+ ENTRY("open_extended", SYS_open_extended, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 277 */
+ ENTRY("umask_extended", SYS_umask_extended, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 278 */
+ ENTRY("stat_extended", SYS_stat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 279 */
+ ENTRY("lstat_extended", SYS_lstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 280 */
+ ENTRY("fstat_extended", SYS_fstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 281 */
+ ENTRY("chmod_extended", SYS_chmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 282 */
+ ENTRY("fchmod_extended", SYS_fchmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 283 */
+ ENTRY("access_extended", SYS_access_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 284 */
+ ENTRY("settid", SYS_settid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 285 */
+ ENTRY("gettid", SYS_gettid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 286 */
+ ENTRY("setsgroups", SYS_setsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 287 */
+ ENTRY("getsgroups", SYS_getsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 288 */
+ ENTRY("setwgroups", SYS_setwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 289 */
+ ENTRY("getwgroups", SYS_getwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 290 */
+ ENTRY("mkfifo_extended", SYS_mkfifo_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 291 */
+ ENTRY("mkdir_extended", SYS_mkdir_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 292 */
+ ENTRY("identitysvc", SYS_identitysvc, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 293 */
+ ENTRY("", 294, no_syscall, 0, CALL_INDIRECT, VOID) /* 294 */
+ ENTRY("", 295, no_syscall, 0, CALL_INDIRECT, VOID) /* 295 */
+ ENTRY("load_shared_file", SYS_load_shared_file, unimpl_unix_syscall, 7, CALL_INDIRECT, VOID) /* 296 */
+ ENTRY("reset_shared_file", SYS_reset_shared_file, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 297 */
+ ENTRY("new_system_shared_regions", SYS_new_system_shared_regions, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 298 */
+ ENTRY("shared_region_map_file_np", SYS_shared_region_map_file_np, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 299 */
+ ENTRY("shared_region_make_private_np", SYS_shared_region_make_private_np, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 300 */
+ ENTRY("", 301, no_syscall, 0, CALL_INDIRECT, VOID) /* 301 */
+ ENTRY("", 302, no_syscall, 0, CALL_INDIRECT, VOID) /* 302 */
+ ENTRY("", 303, no_syscall, 0, CALL_INDIRECT, VOID) /* 303 */
+ ENTRY("", 304, no_syscall, 0, CALL_INDIRECT, VOID) /* 304 */
+ ENTRY("", 305, no_syscall, 0, CALL_INDIRECT, VOID) /* 305 */
+ ENTRY("", 306, no_syscall, 0, CALL_INDIRECT, VOID) /* 306 */
+ ENTRY("", 307, no_syscall, 0, CALL_INDIRECT, VOID) /* 307 */
+ ENTRY("", 308, no_syscall, 0, CALL_INDIRECT, VOID) /* 308 */
+ ENTRY("", 309, no_syscall, 0, CALL_INDIRECT, VOID) /* 309 */
+ ENTRY("getsid", SYS_getsid, getsid, 1, CALL_DIRECT, INT) /* 310 */
+ ENTRY("settid_with_pid", SYS_settid_with_pid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 311 */
+ ENTRY("", 312, no_syscall, 0, CALL_INDIRECT, VOID) /* 312 */
+ ENTRY("aio_fsync", SYS_aio_fsync, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 313 */
+ ENTRY("aio_return", SYS_aio_return, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 314 */
+ ENTRY("aio_suspend", SYS_aio_suspend, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 315 */
+ ENTRY("aio_cancel", SYS_aio_cancel, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 316 */
+ ENTRY("aio_error", SYS_aio_error, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 317 */
+ ENTRY("aio_read", SYS_aio_read, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 318 */
+ ENTRY("aio_write", SYS_aio_write, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 319 */
+ ENTRY("lio_listio", SYS_lio_listio, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 320 */
+ ENTRY("", 321, no_syscall, 0, CALL_INDIRECT, VOID) /* 321 */
+ ENTRY("", 322, no_syscall, 0, CALL_INDIRECT, VOID) /* 322 */
+ ENTRY("", 323, no_syscall, 0, CALL_INDIRECT, VOID) /* 323 */
+ ENTRY("mlockall", SYS_mlockall, mlockall, 1, CALL_DIRECT, INT) /* 324 */
+ ENTRY("munlockall", SYS_munlockall, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 325 */
+ ENTRY("", 326, no_syscall, 0, CALL_INDIRECT, VOID) /* 326 */
+ ENTRY("issetugid", SYS_issetugid, issetugid, 0, CALL_DIRECT, VOID) /* 327 */
+ ENTRY("__pthread_kill", SYS___pthread_kill, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 328 */
+ ENTRY("pthread_sigmask", SYS_pthread_sigmask, pthread_sigmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 329 */
+ ENTRY("sigwait", SYS_sigwait, sigwait, 2, CALL_DIRECT, PTR, PTR) /* 330 */
+ ENTRY("__disable_threadsignal", SYS___disable_threadsignal, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 331 */
+ ENTRY("__pthread_markcancel", SYS___pthread_markcancel, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 332 */
+ ENTRY("__pthread_canceled", SYS___pthread_canceled, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 333 */
+ ENTRY("__semwait_signal", SYS___semwait_signal, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 334 */
+ ENTRY("utrace", SYS_utrace, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 335 */
+ ENTRY("proc_info", SYS_proc_info, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 336 */
+ ENTRY("", 337, no_syscall, 0, CALL_INDIRECT, VOID) /* 337 */
+ ENTRY("", 338, no_syscall, 0, CALL_INDIRECT, VOID) /* 338 */
+ ENTRY("", 339, no_syscall, 0, CALL_INDIRECT, VOID) /* 339 */
+ ENTRY("", 340, no_syscall, 0, CALL_INDIRECT, VOID) /* 340 */
+ ENTRY("", 341, no_syscall, 0, CALL_INDIRECT, VOID) /* 341 */
+ ENTRY("", 342, no_syscall, 0, CALL_INDIRECT, VOID) /* 342 */
+ ENTRY("", 343, no_syscall, 0, CALL_INDIRECT, VOID) /* 343 */
+ ENTRY("", 344, no_syscall, 0, CALL_INDIRECT, VOID) /* 344 */
+ ENTRY("", 345, no_syscall, 0, CALL_INDIRECT, VOID) /* 345 */
+ ENTRY("", 346, no_syscall, 0, CALL_INDIRECT, VOID) /* 346 */
+ ENTRY("", 347, no_syscall, 0, CALL_INDIRECT, VOID) /* 347 */
+ ENTRY("", 348, no_syscall, 0, CALL_INDIRECT, VOID) /* 348 */
+ ENTRY("", 349, no_syscall, 0, CALL_INDIRECT, VOID) /* 349 */
+ ENTRY("audit", SYS_audit, audit, 2, CALL_DIRECT, PTR, INT) /* 350 */
+ ENTRY("auditon", SYS_auditon, auditon, 3, CALL_DIRECT, INT, PTR, INT) /* 351 */
+ ENTRY("", 352, no_syscall, 0, CALL_INDIRECT, VOID) /* 352 */
+ ENTRY("getauid", SYS_getauid, getauid, 1, CALL_DIRECT, PTR) /* 353 */
+ ENTRY("setauid", SYS_setauid, setauid, 1, CALL_DIRECT, PTR) /* 354 */
+ ENTRY("getaudit", SYS_getaudit, getaudit, 1, CALL_DIRECT, PTR) /* 355 */
+ ENTRY("setaudit", SYS_setaudit, setaudit, 1, CALL_DIRECT, PTR) /* 356 */
+ ENTRY("getaudit_addr", SYS_getaudit_addr, getaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 357 */
+ ENTRY("setaudit_addr", SYS_setaudit_addr, setaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 358 */
+ ENTRY("auditctl", SYS_auditctl, auditctl, 1, CALL_DIRECT, PTR) /* 359 */
+ ENTRY("", 360, no_syscall, 0, CALL_INDIRECT, VOID) /* 360 */
+ ENTRY("", 361, no_syscall, 0, CALL_INDIRECT, VOID) /* 361 */
+ ENTRY("kqueue", SYS_kqueue, kqueue, 0, CALL_DIRECT, VOID) /* 362 */
+ ENTRY("kevent", SYS_kevent, kevent, 6, CALL_DIRECT, INT, PTR, INT, PTR, INT, PTR) /* 363 */
+ ENTRY("lchown", SYS_lchown, lchown, 3, CALL_DIRECT, PTR, INT , INT) /* 364 */
+ ENTRY("stack_snapshot", SYS_stack_snapshot, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 365 */
+ ENTRY("", 366, no_syscall, 0, CALL_INDIRECT, VOID) /* 366 */
+ ENTRY("", 367, no_syscall, 0, CALL_INDIRECT, VOID) /* 367 */
+ ENTRY("", 368, no_syscall, 0, CALL_INDIRECT, VOID) /* 368 */
+ ENTRY("", 369, no_syscall, 0, CALL_INDIRECT, VOID) /* 369 */