2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 # This script produces wrapped versions of syscall implementation
7 # functions. The wrappers extract syscall arguments from where the
8 # syscall trampoline saves them.
10 # Note that NaCl modules are always ILP32 and compiled with a
11 # compiler that passes all arguments on the stack, but the service
12 # runtime may be ILP32, LP64, or P64. So we cannot use just char *
13 # in the structure that we overlay on top of the stack memory to
14 # extract system call arguments. All syscall arguments are extracted
15 # as uint32_t first, then cast to the desired type -- pointers are
16 # not valid until they have been translated from user addresses to
17 # system addresses, and this is the responsibility of the actual
18 # system call handlers.
26 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
28 * Automatically generated code. See nacl_syscall_handlers_gen.py
30 * NaCl Server Runtime Service Call abstractions
33 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
34 #include "native_client/src/trusted/service_runtime/sys_exception.h"
35 #include "native_client/src/trusted/service_runtime/sys_fdio.h"
36 #include "native_client/src/trusted/service_runtime/sys_filename.h"
37 #include "native_client/src/trusted/service_runtime/sys_imc.h"
38 #include "native_client/src/trusted/service_runtime/sys_list_mappings.h"
39 #include "native_client/src/trusted/service_runtime/sys_memory.h"
40 #include "native_client/src/trusted/service_runtime/sys_parallel_io.h"
45 TABLE_INITIALIZER = """\
49 void NaClSyscallTableInit() {
51 for (i = 0; i < NACL_MAX_SYSCALLS; ++i) {
52 nacl_syscall[i].handler = &NaClSysNotImplementedDecoder;
60 IMPLEMENTATION_SKELETON = """\
61 /* this function was automagically generated */
62 static int32_t %(name)sDecoder(struct NaClAppThread *natp) {
64 return %(name)s(natp%(arglist)s);
68 * Check that the function being wrapped has the same type as the type
69 * declared in SYSCALL_LIST.
71 static INLINE void AssertSameType_%(name)s(void) {
72 /* This assignment will give an error if the argument types don't match. */
73 int32_t (*dummy)(%(arg_type_list)s) = %(name)s;
74 /* 'dummy' is not actually a parameter but this suppresses the warning. */
75 UNREFERENCED_PARAMETER(dummy);
79 # Our syscall handling code, in nacl_syscall.S, always pushes the
80 # syscall arguments onto the untrusted user stack. The syscall
81 # arguments get snapshotted from there into a per-syscall structure,
82 # to eliminate time-of-check vs time-of-use issues -- we always only
83 # refer to syscall arguments from this snapshot, rather than from the
84 # untrusted memory locations.
88 ('NACL_sys_null', 'NaClSysNull', []),
89 ('NACL_sys_nameservice', 'NaClSysNameService', ['int *desc_in_out']),
90 ('NACL_sys_dup', 'NaClSysDup', ['int oldfd']),
91 ('NACL_sys_dup2', 'NaClSysDup2', ['int oldfd', 'int newfd']),
92 ('NACL_sys_open', 'NaClSysOpen',
93 ['char *pathname', 'int flags', 'int mode']),
94 ('NACL_sys_close', 'NaClSysClose', ['int d']),
95 ('NACL_sys_read', 'NaClSysRead',
96 ['int d', 'void *buf', 'size_t count']),
97 ('NACL_sys_write', 'NaClSysWrite',
98 ['int d', 'void *buf', 'size_t count']),
99 ('NACL_sys_lseek', 'NaClSysLseek',
100 ['int d', 'nacl_abi_off_t *offp', 'int whence']),
101 ('NACL_sys_ioctl', 'NaClSysIoctl',
102 ['int d', 'int request', 'void *arg']),
103 ('NACL_sys_fstat', 'NaClSysFstat',
104 ['int d', 'struct nacl_abi_stat *nasp']),
105 ('NACL_sys_stat', 'NaClSysStat',
106 ['const char *path', 'struct nacl_abi_stat *nasp']),
107 ('NACL_sys_getdents', 'NaClSysGetdents',
108 ['int d', 'void *buf', 'size_t count']),
109 ('NACL_sys_brk', 'NaClSysBrk', ['uintptr_t new_break']),
110 ('NACL_sys_mmap', 'NaClSysMmap',
111 ['void *start', 'size_t length', 'int prot',
112 'int flags', 'int d', 'nacl_abi_off_t *offp']),
113 ('NACL_sys_mprotect', 'NaClSysMprotect',
114 ['uint32_t start', 'size_t length', 'int prot']),
115 ('NACL_sys_list_mappings', 'NaClSysListMappings',
116 ['uint32_t regions', 'uint32_t count']),
117 ('NACL_sys_munmap', 'NaClSysMunmap', ['void *start', 'size_t length']),
118 ('NACL_sys_exit', 'NaClSysExit', ['int status']),
119 ('NACL_sys_getpid', 'NaClSysGetpid', []),
120 ('NACL_sys_thread_exit', 'NaClSysThreadExit',
121 ['int32_t *stack_flag']),
122 ('NACL_sys_gettimeofday', 'NaClSysGetTimeOfDay',
123 ['struct nacl_abi_timeval *tv', 'struct nacl_abi_timezone *tz']),
124 ('NACL_sys_clock', 'NaClSysClock', []),
125 ('NACL_sys_nanosleep', 'NaClSysNanosleep',
126 ['struct nacl_abi_timespec *req', 'struct nacl_abi_timespec *rem']),
127 ('NACL_sys_clock_getres', 'NaClSysClockGetRes',
128 ['int clk_id', 'uint32_t tsp']),
129 ('NACL_sys_clock_gettime', 'NaClSysClockGetTime',
130 ['int clk_id', 'uint32_t tsp']),
131 ('NACL_sys_mkdir', 'NaClSysMkdir', ['uint32_t path', 'int mode']),
132 ('NACL_sys_rmdir', 'NaClSysRmdir', ['uint32_t path']),
133 ('NACL_sys_chdir', 'NaClSysChdir', ['uint32_t path']),
134 ('NACL_sys_getcwd', 'NaClSysGetcwd', ['uint32_t buffer', 'int len']),
135 ('NACL_sys_unlink', 'NaClSysUnlink', ['uint32_t path']),
136 ('NACL_sys_pread', 'NaClSysPRead',
137 ['int32_t d', 'uint32_t usr_addr', 'uint32_t buffer_bytes',
138 'uint32_t offset_addr']),
139 ('NACL_sys_pwrite', 'NaClSysPWrite',
140 ['int32_t d', 'uint32_t usr_addr', 'uint32_t buffer_bytes',
141 'uint32_t offset_addr']),
142 ('NACL_sys_imc_makeboundsock', 'NaClSysImcMakeBoundSock',
144 ('NACL_sys_imc_accept', 'NaClSysImcAccept', ['int d']),
145 ('NACL_sys_imc_connect', 'NaClSysImcConnect', ['int d']),
146 ('NACL_sys_imc_sendmsg', 'NaClSysImcSendmsg',
147 ['int d', 'struct NaClAbiNaClImcMsgHdr *nanimhp', 'int flags']),
148 ('NACL_sys_imc_recvmsg', 'NaClSysImcRecvmsg',
149 ['int d', 'struct NaClAbiNaClImcMsgHdr *nanimhp', 'int flags']),
150 ('NACL_sys_imc_mem_obj_create', 'NaClSysImcMemObjCreate',
152 ('NACL_sys_tls_init', 'NaClSysTlsInit', ['uint32_t thread_ptr']),
153 ('NACL_sys_thread_create', 'NaClSysThreadCreate',
154 ['void *prog_ctr', 'uint32_t stack_ptr',
155 'uint32_t thread_ptr', 'uint32_t second_thread_ptr']),
156 ('NACL_sys_tls_get', 'NaClSysTlsGet', []),
157 ('NACL_sys_thread_nice', 'NaClSysThreadNice', ['const int nice']),
158 ('NACL_sys_mutex_create', 'NaClSysMutexCreate', []),
159 ('NACL_sys_mutex_lock', 'NaClSysMutexLock',
160 ['int32_t mutex_handle']),
161 ('NACL_sys_mutex_unlock', 'NaClSysMutexUnlock',
162 ['int32_t mutex_handle']),
163 ('NACL_sys_mutex_trylock', 'NaClSysMutexTrylock',
164 ['int32_t mutex_handle']),
165 ('NACL_sys_cond_create', 'NaClSysCondCreate', []),
166 ('NACL_sys_cond_wait', 'NaClSysCondWait',
167 ['int32_t cond_handle', 'int32_t mutex_handle']),
168 ('NACL_sys_cond_signal', 'NaClSysCondSignal',
169 ['int32_t cond_handle']),
170 ('NACL_sys_cond_broadcast', 'NaClSysCondBroadcast',
171 ['int32_t cond_handle']),
172 ('NACL_sys_cond_timed_wait_abs', 'NaClSysCondTimedWaitAbs',
173 ['int32_t cond_handle', 'int32_t mutex_handle',
174 'struct nacl_abi_timespec *ts']),
175 ('NACL_sys_imc_socketpair', 'NaClSysImcSocketPair',
176 ['uint32_t descs_out']),
177 ('NACL_sys_sem_create', 'NaClSysSemCreate', ['int32_t init_value']),
178 ('NACL_sys_sem_wait', 'NaClSysSemWait', ['int32_t sem_handle']),
179 ('NACL_sys_sem_post', 'NaClSysSemPost', ['int32_t sem_handle']),
180 ('NACL_sys_sem_get_value', 'NaClSysSemGetValue',
181 ['int32_t sem_handle']),
182 ('NACL_sys_sched_yield', 'NaClSysSchedYield', []),
183 ('NACL_sys_sysconf', 'NaClSysSysconf', ['int32_t name', 'int32_t *result']),
184 ('NACL_sys_dyncode_create', 'NaClSysDyncodeCreate',
185 ['uint32_t dest', 'uint32_t src', 'uint32_t size']),
186 ('NACL_sys_dyncode_modify', 'NaClSysDyncodeModify',
187 ['uint32_t dest', 'uint32_t src', 'uint32_t size']),
188 ('NACL_sys_dyncode_delete', 'NaClSysDyncodeDelete',
189 ['uint32_t dest', 'uint32_t size']),
190 ('NACL_sys_second_tls_set', 'NaClSysSecondTlsSet',
191 ['uint32_t new_value']),
192 ('NACL_sys_second_tls_get', 'NaClSysSecondTlsGet', []),
193 ('NACL_sys_exception_handler', 'NaClSysExceptionHandler',
194 ['uint32_t handler_addr', 'uint32_t old_handler']),
195 ('NACL_sys_exception_stack', 'NaClSysExceptionStack',
196 ['uint32_t stack_addr', 'uint32_t stack_size']),
197 ('NACL_sys_exception_clear_flag', 'NaClSysExceptionClearFlag', []),
198 ('NACL_sys_test_infoleak', 'NaClSysTestInfoLeak', []),
199 ('NACL_sys_test_crash', 'NaClSysTestCrash', ['int crash_type']),
200 ('NACL_sys_futex_wait_abs', 'NaClSysFutexWaitAbs',
201 ['uint32_t addr', 'uint32_t value', 'uint32_t abstime_ptr']),
202 ('NACL_sys_futex_wake', 'NaClSysFutexWake',
203 ['uint32_t addr', 'uint32_t nwake']),
207 # Syscall arguments MUST be declared in a simple-to-parse manner!
208 # They must match the following regexp:
210 ARG_RE = r'\s*((\w+\s+)+\**)\s*(\w+)'
212 # where matchobj.group(1) is the type, and matchobj.group(3) is the
216 def CollapseWhitespaces(s):
217 return re.sub(r'\s+', ' ', s)
220 def ExtractVariable(decl):
221 type_or_idents = re.match(ARG_RE, decl)
222 return type_or_idents.group(3)
225 def ExtractType(decl):
226 type_or_idents = re.match(ARG_RE, decl)
227 return CollapseWhitespaces(type_or_idents.group(1)).strip()
230 def TypeIsPointer(typestr):
231 return '*' in typestr
234 def ArgList(architecture, alist):
242 # avoid cast to pointer from integer of different size
244 extra_cast = '(uintptr_t)'
245 extractedargs += ['(' + t + ') ' + extra_cast
246 + ' p.' + ExtractVariable(arg)]
248 return ', ' + ', '.join(extractedargs)
251 def MemoryArgStruct(architecture, name, alist):
253 return ' NaClCopyDropLock(natp->nap);'
255 margs = [' uint32_t %s' % ExtractVariable(arg)
259 'members' : ';\n'.join(margs) + ';'
266 struct %(name)sArgs {
269 if (!NaClCopyInFromUserAndDropLock(natp->nap, &p, natp->usr_syscall_args,
271 return -NACL_ABI_EFAULT;
277 def PrintSyscallTableInitializer(protos, ostr):
279 for syscall_number, func_name, alist in protos:
280 assign.append(" NaClAddSyscall(%s, &%sDecoder);" %
281 (syscall_number, func_name))
282 # These inlines are no-ops that should be optimized away.
283 # Emit the call just so that they are not reported as unused.
284 assign.append(" AssertSameType_%s();" % func_name)
285 print >>ostr, TABLE_INITIALIZER % "\n".join(assign)
288 def PrintImplSkel(architecture, protos, ostr):
289 print >>ostr, AUTOGEN_HEADER
290 for syscall_number, func_name, alist in protos:
291 values = { 'name' : func_name,
292 'arglist' : ArgList(architecture, alist),
294 ', '.join(['struct NaClAppThread *natp'] + alist),
295 'members' : MemoryArgStruct(architecture, func_name, alist),
297 print >>ostr, IMPLEMENTATION_SKELETON % values
301 usage = 'Usage: nacl_syscall_handlers_gen.py [-f regex] [-a arch]'
302 input_src = sys.stdin
303 output_dst = sys.stdout
307 opts, pargs = getopt.getopt(argv[1:], 'a:i:o:s:')
308 except getopt.error, e:
309 print >>sys.stderr, 'Illegal option:', str(e)
310 print >>sys.stderr, usage
313 for opt, val in opts:
317 input_src = open(val, 'r')
319 output_dst = open(val, 'w')
323 raise Exception('Unknown option: %s' % opt)
326 arch = arch + '-' + subarch
328 # Check naming consistency.
329 for syscall_number, func_name, alist in SYSCALL_LIST:
330 assert syscall_number.startswith('NACL_sys_'), syscall_number
331 name1 = syscall_number[len('NACL_sys_'):].replace('_', '')
332 assert func_name.startswith('NaClSys'), func_name
333 name2 = func_name[len('NaClSys'):].lower()
334 assert name1 == name2, '%r != %r' % (name1, name2)
336 data = input_src.read()
337 protos = SYSCALL_LIST
338 print >>output_dst, data
339 PrintImplSkel(arch, protos, output_dst)
340 PrintSyscallTableInitializer(protos, output_dst)
345 if __name__ == '__main__':
346 sys.exit(main(sys.argv))