blob: 37e356da15343b7dd2e44571e55c9e061914893f [file] [log] [blame]
The Android Open Source Projecta27d2ba2008-10-21 07:00:00 -07001#!/usr/bin/python
2#
3# this tool is used to generate the syscall assmbler templates
4# to be placed into arch-x86/syscalls, as well as the content
5# of arch-x86/linux/_syscalls.h
6#
7
8import sys, os.path, glob, re, string, commands, filecmp, shutil
9
10from bionic_utils import *
11
12# set this to 1 if you want to generate thumb stubs
13gen_thumb_stubs = 0
14
15# set this to 1 if you want to generate ARM EABI stubs
16gen_eabi_stubs = 1
17
18# get the root Bionic directory, simply this script's dirname
19#
20bionic_root = find_bionic_root()
21if not bionic_root:
22 print "could not find the Bionic root directory. aborting"
23 sys.exit(1)
24
25if bionic_root[-1] != '/':
26 bionic_root += "/"
27
28print "bionic_root is %s" % bionic_root
29
30# temp directory where we store all intermediate files
31bionic_temp = "/tmp/bionic_gensyscalls/"
32
33# all architectures, update as you see fit
34all_archs = [ "arm", "x86" ]
35
36def make_dir( path ):
37 if not os.path.exists(path):
38 parent = os.path.dirname(path)
39 if parent:
40 make_dir(parent)
41 os.mkdir(path)
42
43def create_file( relpath ):
44 dir = os.path.dirname( bionic_temp + relpath )
45 make_dir(dir)
46 return open( bionic_temp + relpath, "w" )
47
48# x86 assembler templates for each syscall stub
49#
50
51x86_header = """/* autogenerated by gensyscalls.py */
52#include <sys/linux-syscalls.h>
53
54 .text
55 .type %(fname)s, @function
56 .globl %(fname)s
57 .align 4
58
59%(fname)s:
60"""
61
62x86_registers = [ "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp" ]
63
64x86_call = """ movl $%(idname)s, %%eax
65 int $0x80
66 cmpl $-129, %%eax
67 jb 1f
68 negl %%eax
69 pushl %%eax
70 call __set_errno
71 addl $4, %%esp
72 orl $-1, %%eax
731:
74"""
75
76x86_return = """ ret
77"""
78
79# ARM assembler templates for each syscall stub
80#
81arm_header = """/* autogenerated by gensyscalls.py */
82#include <sys/linux-syscalls.h>
83
84 .text
85 .type %(fname)s, #function
86 .globl %(fname)s
87 .align 4
88 .fnstart
89
90%(fname)s:
91"""
92
93arm_call_default = arm_header + """\
94 swi #%(idname)s
95 movs r0, r0
96 bxpl lr
97 b __set_syscall_errno
98 .fnend
99"""
100
101arm_call_long = arm_header + """\
102 .save {r4, r5, lr}
103 stmfd sp!, {r4, r5, lr}
104 ldr r4, [sp, #12]
105 ldr r5, [sp, #16]
106 swi # %(idname)s
107 ldmfd sp!, {r4, r5, lr}
108 movs r0, r0
109 bxpl lr
110 b __set_syscall_errno
111 .fnend
112"""
113
114arm_eabi_call_default = arm_header + """\
115 .save {r4, r7}
116 stmfd sp!, {r4, r7}
117 ldr r7, =%(idname)s
118 swi #0
119 ldmfd sp!, {r4, r7}
120 movs r0, r0
121 bxpl lr
122 b __set_syscall_errno
123 .fnend
124"""
125
126arm_eabi_call_long = arm_header + """\
127 mov ip, sp
128 .save {r4, r5, r6, r7}
129 stmfd sp!, {r4, r5, r6, r7}
130 ldmfd ip, {r4, r5, r6}
131 ldr r7, =%(idname)s
132 swi #0
133 ldmfd sp!, {r4, r5, r6, r7}
134 movs r0, r0
135 bxpl lr
136 b __set_syscall_errno
137 .fnend
138"""
139
140# ARM thumb assembler templates for each syscall stub
141#
142thumb_header = """/* autogenerated by gensyscalls.py */
143 .text
144 .type %(fname)s, #function
145 .globl %(fname)s
146 .align 4
147 .thumb_func
148 .fnstart
149
150#define __thumb__
151#include <sys/linux-syscalls.h>
152
153
154%(fname)s:
155"""
156
157thumb_call_default = thumb_header + """\
158 .save {r7,lr}
159 push {r7,lr}
160 ldr r7, =%(idname)s
161 swi #0
162 tst r0, r0
163 bmi 1f
164 pop {r7,pc}
1651:
166 neg r0, r0
167 ldr r1, =__set_errno
168 blx r1
169 pop {r7,pc}
170 .fnend
171"""
172
173thumb_call_long = thumb_header + """\
174 .save {r4,r5,r7,lr}
175 push {r4,r5,r7,lr}
176 ldr r4, [sp,#16]
177 ldr r5, [sp,#20]
178 ldr r7, =%(idname)s
179 swi #0
180 tst r0, r0
181 bmi 1f
182 pop {r4,r5,r7,pc}
1831:
184 neg r0, r0
185 ldr r1, =__set_errno
186 blx r1
187 pop {r4,r5,r7,pc}
188 .fnend
189"""
190
191
192class State:
193 def __init__(self):
194 self.old_stubs = []
195 self.new_stubs = []
196 self.other_files = []
197 self.syscalls = []
198
199 def x86_genstub(self,fname, numparams, idname):
200 t = { "fname" : fname,
201 "idname" : idname }
202
203 result = x86_header % t
204 stack_bias = 4
205 for r in range(numparams):
206 result += " pushl " + x86_registers[r] + "\n"
207 stack_bias += 4
208
209 for r in range(numparams):
210 result += " mov %d(%%esp), %s" % (stack_bias+r*4, x86_registers[r]) + "\n"
211
212 result += x86_call % t
213
214 for r in range(numparams):
215 result += " popl " + x86_registers[numparams-r-1] + "\n"
216
217 result += x86_return
218 return result
219
220
221 def arm_genstub(self,fname, flags, idname):
222 t = { "fname" : fname,
223 "idname" : idname }
224 if flags:
225 numargs = int(flags)
226 if numargs > 4:
227 return arm_call_long % t
228 return arm_call_default % t
229
230
231 def arm_eabi_genstub(self,fname, flags, idname):
232 t = { "fname" : fname,
233 "idname" : idname }
234 if flags:
235 numargs = int(flags)
236 if numargs > 4:
237 return arm_eabi_call_long % t
238 return arm_eabi_call_default % t
239
240
241 def thumb_genstub(self,fname, flags, idname):
242 t = { "fname" : fname,
243 "idname" : idname }
244 if flags:
245 numargs = int(flags)
246 if numargs > 4:
247 return thumb_call_long % t
248 return thumb_call_default % t
249
250
251 def process_file(self,input):
252 parser = SysCallsTxtParser()
253 parser.parse_file(input)
254 self.syscalls = parser.syscalls
255 parser = None
256
257 for t in self.syscalls:
258 syscall_func = t["func"]
259 syscall_params = t["params"]
260 syscall_name = t["name"]
261
262 if t["id"] >= 0:
263 if gen_thumb_stubs:
264 t["asm-thumb"] = self.thumb_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
265 else:
266 if gen_eabi_stubs:
267 t["asm-arm"] = self.arm_eabi_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
268 else:
269 t["asm-arm"] = self.arm_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
270
271 if t["id2"] >= 0:
272 t["asm-x86"] = self.x86_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
273
274 def gen_NR_syscall(self,fp,name,id):
275 fp.write( "#define __NR_%-25s (__NR_SYSCALL_BASE + %d)\n" % (name,id) )
276
277 # now dump the content of linux/_syscalls.h
278 def gen_linux_syscalls_h(self):
279 path = "include/sys/linux-syscalls.h"
280 D( "generating "+path )
281 fp = create_file( path )
282 fp.write( "/* auto-generated by gensyscalls.py, do not touch */\n" )
283 fp.write( "#ifndef _BIONIC_LINUX_SYSCALLS_H_\n\n" )
284 fp.write( "#if !defined __ASM_ARM_UNISTD_H && !defined __ASM_I386_UNISTD_H\n" )
285 fp.write( "#if defined __arm__ && !defined __ARM_EABI__ && !defined __thumb__\n" )
286 fp.write( " # define __NR_SYSCALL_BASE 0x900000\n" )
287 fp.write( " #else\n" )
288 fp.write( " # define __NR_SYSCALL_BASE 0\n" )
289 fp.write( " #endif\n\n" )
290
291 # first, all common syscalls
292 for sc in self.syscalls:
293 sc_id = sc["id"]
294 sc_id2 = sc["id2"]
295 sc_name = sc["name"]
296 if sc_id == sc_id2 and sc_id >= 0:
297 self.gen_NR_syscall( fp, sc_name, sc_id )
298
299 # now, all arm-specific syscalls
300 fp.write( "\n#ifdef __arm__\n" );
301 for sc in self.syscalls:
302 sc_id = sc["id"]
303 sc_id2 = sc["id2"]
304 sc_name = sc["name"]
305 if sc_id != sc_id2 and sc_id >= 0:
306 self.gen_NR_syscall( fp, sc_name, sc_id )
307 fp.write( "#endif\n" );
308
309 # finally, all i386-specific syscalls
310 fp.write( "\n#ifdef __i386__\n" );
311 for sc in self.syscalls:
312 sc_id = sc["id"]
313 sc_id2 = sc["id2"]
314 sc_name = sc["name"]
315 if sc_id != sc_id2 and sc_id2 >= 0:
316 self.gen_NR_syscall( fp, sc_name, sc_id2 )
317 fp.write( "#endif\n" );
318
319 fp.write( "\n#endif\n" )
320 fp.write( "\n#endif /* _BIONIC_LINUX_SYSCALLS_H_ */\n" );
321 fp.close()
322 self.other_files.append( path )
323
324
325 # now dump the content of linux/_syscalls.h
326 def gen_linux_unistd_h(self):
327 path = "include/sys/linux-unistd.h"
328 D( "generating "+path )
329 fp = create_file( path )
330 fp.write( "/* auto-generated by gensyscalls.py, do not touch */\n" )
331 fp.write( "#ifndef _BIONIC_LINUX_UNISTD_H_\n\n" );
332 fp.write( "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n" )
333
334 for sc in self.syscalls:
335 fp.write( sc["decl"]+"\n" )
336
337 fp.write( "#ifdef __cplusplus\n}\n#endif\n" )
338 fp.write( "\n#endif /* _BIONIC_LINUX_UNISTD_H_ */\n" );
339 fp.close()
340 self.other_files.append( path )
341
342 # now dump the contents of syscalls.mk
343 def gen_arch_arm_syscalls_mk(self):
344 path = "arch-arm/syscalls.mk"
345 D( "generating "+path )
346 fp = create_file( path )
347 fp.write( "# auto-generated by gensyscalls.py, do not touch\n" )
348 fp.write( "syscall_src := \n" )
349 for sc in self.syscalls:
350 if sc["id"] >= 0:
351 fp.write( "syscall_src += arch-arm/syscalls/%s.S\n" % sc["func"] )
352 fp.close()
353 self.other_files.append( path )
354
355 # now generate each syscall stub
356 def gen_syscall_stubs(self):
357 for sc in self.syscalls:
358 if sc.has_key("asm-arm"):
359 fname = "arch-arm/syscalls/%s.S" % sc["func"]
360 D( ">>> generating "+fname )
361 fp = create_file( fname )
362 fp.write(sc["asm-arm"])
363 fp.close()
364 self.new_stubs.append( fname )
365
366 if sc.has_key("asm-thumb"):
367 fname = "arch-arm/syscalls/%s.S" % sc["func"]
368 D( ">>> generating "+fname )
369 fp = create_file( fname )
370 fp.write(sc["asm-thumb"])
371 fp.close()
372 self.new_stubs.append( fname )
373
374 if sc.has_key("asm-x86"):
375 fname = "arch-x86/syscalls/%s.S" % sc["func"]
376 D( ">>> generating "+fname )
377 fp = create_file( fname )
378 fp.write(sc["asm-x86"])
379 fp.close()
380 self.new_stubs.append( fname )
381
382
383 def regenerate(self):
384 D( "scanning for existing architecture-specific stub files" )
385
386 bionic_root_len = len(bionic_root)
387
388 for arch in all_archs:
389 arch_path = bionic_root + "arch-" + arch
390 D( "scanning " + arch_path )
391 files = glob.glob( arch_path + "/syscalls/*.S" )
392 for f in files:
393 self.old_stubs.append( f[bionic_root_len:] )
394
395 D( "found %d stub files" % len(self.old_stubs) )
396
397 if not os.path.exists( bionic_temp ):
398 D( "creating %s" % bionic_temp )
399 os.mkdir( bionic_temp )
400
401# D( "p4 editing source files" )
402# for arch in all_archs:
403# commands.getoutput( "p4 edit " + arch + "/syscalls/*.S " )
404# commands.getoutput( "p4 edit " + arch + "/syscalls.mk" )
405# commands.getoutput( "p4 edit " + bionic_root + "include/sys/linux-syscalls.h" )
406
407 D( "re-generating stubs and support files" )
408
409 self.gen_linux_syscalls_h()
410 self.gen_arch_arm_syscalls_mk()
411 self.gen_linux_unistd_h()
412 self.gen_syscall_stubs()
413
414 D( "comparing files" )
415 adds = []
416 edits = []
417
418 for stub in self.new_stubs + self.other_files:
419 if not os.path.exists( bionic_root + stub ):
420 # new file, P4 add it
421 D( "new file: " + stub)
422 adds.append( bionic_root + stub )
423 shutil.copyfile( bionic_temp + stub, bionic_root + stub )
424
425 elif not filecmp.cmp( bionic_temp + stub, bionic_root + stub ):
426 D( "changed file: " + stub)
427 edits.append( stub )
428
429 deletes = []
430 for stub in self.old_stubs:
431 if not stub in self.new_stubs:
432 D( "deleted file: " + stub)
433 deletes.append( bionic_root + stub )
434
435
436 if adds:
437 commands.getoutput( "p4 add " + string.join( adds, " " ) )
438 if deletes:
439 commands.getoutput( "p4 delete " + string.join( deletes, " " ) )
440 if edits:
441 commands.getoutput( "p4 edit " + string.join( edits, " " ) )
442 for file in edits:
443 shutil.copyfile( bionic_temp + file, bionic_root + file )
444
445 D("ready to go !!")
446
447D_setlevel(1)
448
449state = State()
450state.process_file(bionic_root+"SYSCALLS.TXT")
451state.regenerate()