blob: 0271a04c5ce0d471233352ed00cf159118db6ae6 [file] [log] [blame]
Stephen Crane77bb5642017-08-31 15:08:26 -07001#!/usr/bin/env python
Pavel Chupinf12a18b2012-12-12 13:11:48 +04002
3# This tool is used to generate the assembler system call stubs,
4# the header files listing all available system calls, and the
5# makefiles used to build all the stubs.
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -07006
Christopher Ferris01bd32e2014-08-05 12:19:27 -07007import atexit
Elliott Hughes103ccde2013-10-16 14:27:59 -07008import commands
9import filecmp
10import glob
Elliott Hughes103ccde2013-10-16 14:27:59 -070011import re
12import shutil
13import stat
Elliott Hughesdc1fb702014-08-20 11:16:11 -070014import string
Elliott Hughes103ccde2013-10-16 14:27:59 -070015import sys
Christopher Ferris01bd32e2014-08-05 12:19:27 -070016import tempfile
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -070017
Elliott Hughesdc1fb702014-08-20 11:16:11 -070018
Elliott Hughesc2faf232020-02-03 17:56:06 -080019SupportedArchitectures = [ "arm", "arm64", "x86", "x86_64" ]
Elliott Hughesdc1fb702014-08-20 11:16:11 -070020
Elliott Hughesd67b0372019-04-15 14:18:26 -070021syscall_stub_header = \
Elliott Hughes103ccde2013-10-16 14:27:59 -070022"""
Elliott Hughes0437f3f2013-10-07 23:53:13 -070023ENTRY(%(func)s)
Pavel Chupinf12a18b2012-12-12 13:11:48 +040024"""
25
Elliott Hughes0437f3f2013-10-07 23:53:13 -070026
Elliott Hughes0437f3f2013-10-07 23:53:13 -070027#
28# ARM assembler templates for each syscall stub
29#
30
31arm_eabi_call_default = syscall_stub_header + """\
32 mov ip, r7
Christopher Ferrisf5a91232016-04-27 18:31:02 -070033 .cfi_register r7, ip
Elliott Hughes0437f3f2013-10-07 23:53:13 -070034 ldr r7, =%(__NR_name)s
35 swi #0
36 mov r7, ip
Christopher Ferrisf5a91232016-04-27 18:31:02 -070037 .cfi_restore r7
Elliott Hughes0437f3f2013-10-07 23:53:13 -070038 cmn r0, #(MAX_ERRNO + 1)
39 bxls lr
40 neg r0, r0
Elliott Hughes011e1112014-09-08 15:25:01 -070041 b __set_errno_internal
Elliott Hughes0437f3f2013-10-07 23:53:13 -070042END(%(func)s)
43"""
44
45arm_eabi_call_long = syscall_stub_header + """\
46 mov ip, sp
Elliott Hughes0437f3f2013-10-07 23:53:13 -070047 stmfd sp!, {r4, r5, r6, r7}
Christopher Ferrised459702013-12-02 17:44:53 -080048 .cfi_def_cfa_offset 16
49 .cfi_rel_offset r4, 0
50 .cfi_rel_offset r5, 4
51 .cfi_rel_offset r6, 8
52 .cfi_rel_offset r7, 12
Elliott Hughes0437f3f2013-10-07 23:53:13 -070053 ldmfd ip, {r4, r5, r6}
54 ldr r7, =%(__NR_name)s
55 swi #0
56 ldmfd sp!, {r4, r5, r6, r7}
Christopher Ferrised459702013-12-02 17:44:53 -080057 .cfi_def_cfa_offset 0
Elliott Hughes0437f3f2013-10-07 23:53:13 -070058 cmn r0, #(MAX_ERRNO + 1)
59 bxls lr
60 neg r0, r0
Elliott Hughes011e1112014-09-08 15:25:01 -070061 b __set_errno_internal
Elliott Hughes0437f3f2013-10-07 23:53:13 -070062END(%(func)s)
63"""
64
65
66#
Elliott Hughesd67b0372019-04-15 14:18:26 -070067# Arm64 assembler template for each syscall stub
Colin Crossd1973ca2014-01-21 19:50:58 -080068#
69
70arm64_call = syscall_stub_header + """\
Colin Crossd1973ca2014-01-21 19:50:58 -080071 mov x8, %(__NR_name)s
72 svc #0
73
Colin Crossd1973ca2014-01-21 19:50:58 -080074 cmn x0, #(MAX_ERRNO + 1)
75 cneg x0, x0, hi
Elliott Hughes011e1112014-09-08 15:25:01 -070076 b.hi __set_errno_internal
Colin Crossd1973ca2014-01-21 19:50:58 -080077
78 ret
79END(%(func)s)
80"""
81
82
83#
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -070084# x86 assembler templates for each syscall stub
85#
86
Christopher Ferrise4bc7562014-01-06 16:39:10 -080087x86_registers = [ "ebx", "ecx", "edx", "esi", "edi", "ebp" ]
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -070088
Mingwei Shibe910522015-11-12 07:02:14 +000089x86_call_prepare = """\
90
91 call __kernel_syscall
92 pushl %eax
93 .cfi_adjust_cfa_offset 4
94 .cfi_rel_offset eax, 0
95
96"""
97
Elliott Hughes0437f3f2013-10-07 23:53:13 -070098x86_call = """\
99 movl $%(__NR_name)s, %%eax
Mingwei Shibe910522015-11-12 07:02:14 +0000100 call *(%%esp)
101 addl $4, %%esp
102
Elliott Hughes9aceab52013-03-12 14:57:30 -0700103 cmpl $-MAX_ERRNO, %%eax
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700104 jb 1f
105 negl %%eax
106 pushl %%eax
Elliott Hughes011e1112014-09-08 15:25:01 -0700107 call __set_errno_internal
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700108 addl $4, %%esp
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -07001091:
110"""
111
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700112x86_return = """\
113 ret
114END(%(func)s)
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700115"""
116
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700117
Elliott Hughescd6780b2013-02-07 14:07:00 -0800118#
Elliott Hughesd67b0372019-04-15 14:18:26 -0700119# x86_64 assembler template for each syscall stub
Pavel Chupinf12a18b2012-12-12 13:11:48 +0400120#
121
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700122x86_64_call = """\
123 movl $%(__NR_name)s, %%eax
Pavel Chupinf12a18b2012-12-12 13:11:48 +0400124 syscall
125 cmpq $-MAX_ERRNO, %%rax
126 jb 1f
127 negl %%eax
128 movl %%eax, %%edi
Elliott Hughes011e1112014-09-08 15:25:01 -0700129 call __set_errno_internal
Pavel Chupinf12a18b2012-12-12 13:11:48 +04001301:
131 ret
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700132END(%(func)s)
Pavel Chupinf12a18b2012-12-12 13:11:48 +0400133"""
134
Raghu Gandham1fa0d842012-01-27 17:51:42 -0800135
David 'Digit' Turner95d751f2010-12-16 16:47:14 +0100136def param_uses_64bits(param):
137 """Returns True iff a syscall parameter description corresponds
138 to a 64-bit type."""
139 param = param.strip()
140 # First, check that the param type begins with one of the known
141 # 64-bit types.
142 if not ( \
143 param.startswith("int64_t") or param.startswith("uint64_t") or \
144 param.startswith("loff_t") or param.startswith("off64_t") or \
145 param.startswith("long long") or param.startswith("unsigned long long") or
146 param.startswith("signed long long") ):
147 return False
148
149 # Second, check that there is no pointer type here
150 if param.find("*") >= 0:
151 return False
152
153 # Ok
154 return True
155
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700156
David 'Digit' Turner95d751f2010-12-16 16:47:14 +0100157def count_arm_param_registers(params):
158 """This function is used to count the number of register used
Elliott Hughescd6780b2013-02-07 14:07:00 -0800159 to pass parameters when invoking an ARM system call.
David 'Digit' Turner95d751f2010-12-16 16:47:14 +0100160 This is because the ARM EABI mandates that 64-bit quantities
161 must be passed in an even+odd register pair. So, for example,
162 something like:
163
164 foo(int fd, off64_t pos)
165
166 would actually need 4 registers:
167 r0 -> int
168 r1 -> unused
169 r2-r3 -> pos
170 """
171 count = 0
172 for param in params:
173 if param_uses_64bits(param):
174 if (count & 1) != 0:
175 count += 1
176 count += 2
177 else:
178 count += 1
179 return count
180
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700181
David 'Digit' Turner95d751f2010-12-16 16:47:14 +0100182def count_generic_param_registers(params):
183 count = 0
184 for param in params:
185 if param_uses_64bits(param):
186 count += 2
187 else:
188 count += 1
189 return count
190
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700191
Pavel Chupinf12a18b2012-12-12 13:11:48 +0400192def count_generic_param_registers64(params):
193 count = 0
194 for param in params:
195 count += 1
196 return count
197
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700198
Elliott Hughescda62092013-03-22 13:50:44 -0700199# This lets us support regular system calls like __NR_write and also weird
200# ones like __ARM_NR_cacheflush, where the NR doesn't come at the start.
201def make__NR_name(name):
Christopher Ferris01bd32e2014-08-05 12:19:27 -0700202 if name.startswith("__ARM_NR_"):
Elliott Hughescda62092013-03-22 13:50:44 -0700203 return name
204 else:
205 return "__NR_%s" % (name)
206
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700207
Elliott Hughesfff6e272013-10-24 17:03:20 -0700208def add_footer(pointer_length, stub, syscall):
209 # Add any aliases for this syscall.
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700210 aliases = syscall["aliases"]
211 for alias in aliases:
Christopher Ferrisfa5faa02015-03-24 16:50:46 -0700212 stub += "\nALIAS_SYMBOL(%s, %s)\n" % (alias, syscall["func"])
Elliott Hughesfff6e272013-10-24 17:03:20 -0700213
Nick Kralevich00490ae2015-02-03 11:27:25 -0800214 # Use hidden visibility on LP64 for any functions beginning with underscores.
Elliott Hughes50080a22019-06-19 12:47:53 -0700215 if pointer_length == 64 and syscall["func"].startswith("__"):
Elliott Hughesd465eb42014-02-19 18:59:19 -0800216 stub += '.hidden ' + syscall["func"] + '\n'
Elliott Hughesfff6e272013-10-24 17:03:20 -0700217
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700218 return stub
219
220
221def arm_eabi_genstub(syscall):
222 num_regs = count_arm_param_registers(syscall["params"])
223 if num_regs > 4:
224 return arm_eabi_call_long % syscall
225 return arm_eabi_call_default % syscall
226
227
Colin Crossd1973ca2014-01-21 19:50:58 -0800228def arm64_genstub(syscall):
229 return arm64_call % syscall
230
231
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700232def x86_genstub(syscall):
233 result = syscall_stub_header % syscall
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700234
235 numparams = count_generic_param_registers(syscall["params"])
Mingwei Shibe910522015-11-12 07:02:14 +0000236 stack_bias = numparams*4 + 8
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800237 offset = 0
238 mov_result = ""
Christopher Ferris15b91e92014-05-29 18:17:09 -0700239 first_push = True
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800240 for register in x86_registers[:numparams]:
241 result += " pushl %%%s\n" % register
Christopher Ferris15b91e92014-05-29 18:17:09 -0700242 if first_push:
243 result += " .cfi_def_cfa_offset 8\n"
244 result += " .cfi_rel_offset %s, 0\n" % register
245 first_push = False
246 else:
247 result += " .cfi_adjust_cfa_offset 4\n"
248 result += " .cfi_rel_offset %s, 0\n" % register
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800249 mov_result += " mov %d(%%esp), %%%s\n" % (stack_bias+offset, register)
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800250 offset += 4
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700251
Mingwei Shibe910522015-11-12 07:02:14 +0000252 result += x86_call_prepare
Christopher Ferris15b91e92014-05-29 18:17:09 -0700253 result += mov_result
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700254 result += x86_call % syscall
255
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800256 for register in reversed(x86_registers[:numparams]):
257 result += " popl %%%s\n" % register
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700258
259 result += x86_return % syscall
260 return result
261
Serban Constantinescufeaa89a2013-10-07 16:49:09 +0100262
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700263def x86_genstub_socketcall(syscall):
264 # %ebx <--- Argument 1 - The call id of the needed vectored
265 # syscall (socket, bind, recv, etc)
266 # %ecx <--- Argument 2 - Pointer to the rest of the arguments
267 # from the original function called (socket())
268
269 result = syscall_stub_header % syscall
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700270
271 # save the regs we need
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800272 result += " pushl %ebx\n"
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800273 result += " .cfi_def_cfa_offset 8\n"
274 result += " .cfi_rel_offset ebx, 0\n"
Christopher Ferris15b91e92014-05-29 18:17:09 -0700275 result += " pushl %ecx\n"
276 result += " .cfi_adjust_cfa_offset 4\n"
277 result += " .cfi_rel_offset ecx, 0\n"
Mingwei Shibe910522015-11-12 07:02:14 +0000278 stack_bias = 16
279
280 result += x86_call_prepare
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700281
282 # set the call id (%ebx)
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800283 result += " mov $%d, %%ebx\n" % syscall["socketcall_id"]
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700284
285 # set the pointer to the rest of the args into %ecx
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800286 result += " mov %esp, %ecx\n"
287 result += " addl $%d, %%ecx\n" % (stack_bias)
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700288
289 # now do the syscall code itself
290 result += x86_call % syscall
291
292 # now restore the saved regs
Christopher Ferrise4bc7562014-01-06 16:39:10 -0800293 result += " popl %ecx\n"
294 result += " popl %ebx\n"
Elliott Hughes0437f3f2013-10-07 23:53:13 -0700295
296 # epilog
297 result += x86_return % syscall
298 return result
299
300
301def x86_64_genstub(syscall):
302 result = syscall_stub_header % syscall
303 num_regs = count_generic_param_registers64(syscall["params"])
304 if (num_regs > 3):
305 # rcx is used as 4th argument. Kernel wants it at r10.
306 result += " movq %rcx, %r10\n"
307
308 result += x86_64_call % syscall
309 return result
310
311
Elliott Hughesdc1fb702014-08-20 11:16:11 -0700312class SysCallsTxtParser:
313 def __init__(self):
314 self.syscalls = []
315 self.lineno = 0
316
317 def E(self, msg):
318 print "%d: %s" % (self.lineno, msg)
319
320 def parse_line(self, line):
321 """ parse a syscall spec line.
322
323 line processing, format is
324 return type func_name[|alias_list][:syscall_name[:socketcall_id]] ( [paramlist] ) architecture_list
325 """
326 pos_lparen = line.find('(')
327 E = self.E
328 if pos_lparen < 0:
329 E("missing left parenthesis in '%s'" % line)
330 return
331
332 pos_rparen = line.rfind(')')
333 if pos_rparen < 0 or pos_rparen <= pos_lparen:
334 E("missing or misplaced right parenthesis in '%s'" % line)
335 return
336
337 return_type = line[:pos_lparen].strip().split()
338 if len(return_type) < 2:
339 E("missing return type in '%s'" % line)
340 return
341
342 syscall_func = return_type[-1]
343 return_type = string.join(return_type[:-1],' ')
344 socketcall_id = -1
345
346 pos_colon = syscall_func.find(':')
347 if pos_colon < 0:
348 syscall_name = syscall_func
349 else:
350 if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
351 E("misplaced colon in '%s'" % line)
352 return
353
354 # now find if there is a socketcall_id for a dispatch-type syscall
355 # after the optional 2nd colon
356 pos_colon2 = syscall_func.find(':', pos_colon + 1)
357 if pos_colon2 < 0:
358 syscall_name = syscall_func[pos_colon+1:]
359 syscall_func = syscall_func[:pos_colon]
360 else:
361 if pos_colon2+1 >= len(syscall_func):
362 E("misplaced colon2 in '%s'" % line)
363 return
364 syscall_name = syscall_func[(pos_colon+1):pos_colon2]
365 socketcall_id = int(syscall_func[pos_colon2+1:])
366 syscall_func = syscall_func[:pos_colon]
367
368 alias_delim = syscall_func.find('|')
369 if alias_delim > 0:
370 alias_list = syscall_func[alias_delim+1:].strip()
371 syscall_func = syscall_func[:alias_delim]
372 alias_delim = syscall_name.find('|')
373 if alias_delim > 0:
374 syscall_name = syscall_name[:alias_delim]
375 syscall_aliases = string.split(alias_list, ',')
376 else:
377 syscall_aliases = []
378
379 if pos_rparen > pos_lparen+1:
380 syscall_params = line[pos_lparen+1:pos_rparen].split(',')
381 params = string.join(syscall_params,',')
382 else:
383 syscall_params = []
384 params = "void"
385
386 t = {
387 "name" : syscall_name,
388 "func" : syscall_func,
389 "aliases" : syscall_aliases,
390 "params" : syscall_params,
391 "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params),
392 "socketcall_id" : socketcall_id
393 }
394
395 # Parse the architecture list.
396 arch_list = line[pos_rparen+1:].strip()
397 if arch_list == "all":
Elliott Hughesae03b122019-09-17 16:37:05 -0700398 for arch in SupportedArchitectures:
Elliott Hughesdc1fb702014-08-20 11:16:11 -0700399 t[arch] = True
400 else:
401 for arch in string.split(arch_list, ','):
Elliott Hughes2b499042020-02-13 14:21:55 -0800402 if arch == "lp32":
403 for arch in SupportedArchitectures:
404 if "64" not in arch:
405 t[arch] = True
406 elif arch == "lp64":
407 for arch in SupportedArchitectures:
408 if "64" in arch:
409 t[arch] = True
410 elif arch in SupportedArchitectures:
Elliott Hughesdc1fb702014-08-20 11:16:11 -0700411 t[arch] = True
412 else:
413 E("invalid syscall architecture '%s' in '%s'" % (arch, line))
414 return
415
416 self.syscalls.append(t)
417
Paul Lawrence7ea40902017-02-14 13:32:23 -0800418 def parse_open_file(self, fp):
419 for line in fp:
Elliott Hughesdc1fb702014-08-20 11:16:11 -0700420 self.lineno += 1
421 line = line.strip()
422 if not line: continue
423 if line[0] == '#': continue
424 self.parse_line(line)
425
Paul Lawrence7ea40902017-02-14 13:32:23 -0800426 def parse_file(self, file_path):
Paul Lawrence7ea40902017-02-14 13:32:23 -0800427 with open(file_path) as fp:
Alessio Balsini93d4f8b2017-04-11 18:27:29 +0200428 self.parse_open_file(fp)
Elliott Hughesdc1fb702014-08-20 11:16:11 -0700429
430
John Catere86e5052019-09-26 14:47:03 -0400431def main(arch, syscall_file):
Elliott Hughes782c4852019-04-16 12:31:00 -0700432 parser = SysCallsTxtParser()
John Catere86e5052019-09-26 14:47:03 -0400433 parser.parse_file(syscall_file)
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700434
Elliott Hughes782c4852019-04-16 12:31:00 -0700435 for syscall in parser.syscalls:
436 syscall["__NR_name"] = make__NR_name(syscall["name"])
Pavel Chupinf12a18b2012-12-12 13:11:48 +0400437
Elliott Hughes782c4852019-04-16 12:31:00 -0700438 if syscall.has_key("arm"):
439 syscall["asm-arm"] = add_footer(32, arm_eabi_genstub(syscall), syscall)
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700440
Elliott Hughes782c4852019-04-16 12:31:00 -0700441 if syscall.has_key("arm64"):
442 syscall["asm-arm64"] = add_footer(64, arm64_genstub(syscall), syscall)
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700443
Elliott Hughes782c4852019-04-16 12:31:00 -0700444 if syscall.has_key("x86"):
445 if syscall["socketcall_id"] >= 0:
446 syscall["asm-x86"] = add_footer(32, x86_genstub_socketcall(syscall), syscall)
447 else:
448 syscall["asm-x86"] = add_footer(32, x86_genstub(syscall), syscall)
449 elif syscall["socketcall_id"] >= 0:
450 E("socketcall_id for dispatch syscalls is only supported for x86 in '%s'" % t)
451 return
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700452
Elliott Hughes782c4852019-04-16 12:31:00 -0700453 if syscall.has_key("x86_64"):
454 syscall["asm-x86_64"] = add_footer(64, x86_64_genstub(syscall), syscall)
The Android Open Source Project4e468ed2008-12-17 18:03:48 -0800455
Elliott Hughes782c4852019-04-16 12:31:00 -0700456 print("/* Generated by gensyscalls.py. Do not edit. */\n")
457 print("#include <private/bionic_asm.h>\n")
458 for syscall in parser.syscalls:
459 if syscall.has_key("asm-%s" % arch):
460 print(syscall["asm-%s" % arch])
Chris Dearman50432122014-02-05 16:59:23 -0800461
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -0700462
Paul Lawrenceeabc3522016-11-11 11:33:42 -0800463if __name__ == "__main__":
John Catere86e5052019-09-26 14:47:03 -0400464 if len(sys.argv) < 2:
465 print "Usage: gensyscalls.py ARCH SOURCE_FILE"
466 sys.exit(1)
467
468 arch = sys.argv[1]
469 syscall_file = sys.argv[2]
470 main(arch, syscall_file)