gensyscalls.py revision a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349
1#!/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() 452