diff options
Diffstat (limited to 'libc/tools/gensyscalls.py')
-rwxr-xr-x | libc/tools/gensyscalls.py | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py new file mode 100755 index 0000000..37e356d --- /dev/null +++ b/libc/tools/gensyscalls.py @@ -0,0 +1,451 @@ +#!/usr/bin/python +# +# this tool is used to generate the syscall assmbler templates +# to be placed into arch-x86/syscalls, as well as the content +# of arch-x86/linux/_syscalls.h +# + +import sys, os.path, glob, re, string, commands, filecmp, shutil + +from bionic_utils import * + +# set this to 1 if you want to generate thumb stubs +gen_thumb_stubs = 0 + +# set this to 1 if you want to generate ARM EABI stubs +gen_eabi_stubs = 1 + +# get the root Bionic directory, simply this script's dirname +# +bionic_root = find_bionic_root() +if not bionic_root: + print "could not find the Bionic root directory. aborting" + sys.exit(1) + +if bionic_root[-1] != '/': + bionic_root += "/" + +print "bionic_root is %s" % bionic_root + +# temp directory where we store all intermediate files +bionic_temp = "/tmp/bionic_gensyscalls/" + +# all architectures, update as you see fit +all_archs = [ "arm", "x86" ] + +def make_dir( path ): + if not os.path.exists(path): + parent = os.path.dirname(path) + if parent: + make_dir(parent) + os.mkdir(path) + +def create_file( relpath ): + dir = os.path.dirname( bionic_temp + relpath ) + make_dir(dir) + return open( bionic_temp + relpath, "w" ) + +# x86 assembler templates for each syscall stub +# + +x86_header = """/* autogenerated by gensyscalls.py */ +#include <sys/linux-syscalls.h> + + .text + .type %(fname)s, @function + .globl %(fname)s + .align 4 + +%(fname)s: +""" + +x86_registers = [ "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp" ] + +x86_call = """ movl $%(idname)s, %%eax + int $0x80 + cmpl $-129, %%eax + jb 1f + negl %%eax + pushl %%eax + call __set_errno + addl $4, %%esp + orl $-1, %%eax +1: +""" + +x86_return = """ ret +""" + +# ARM assembler templates for each syscall stub +# +arm_header = """/* autogenerated by gensyscalls.py */ +#include <sys/linux-syscalls.h> + + .text + .type %(fname)s, #function + .globl %(fname)s + .align 4 + .fnstart + +%(fname)s: +""" + +arm_call_default = arm_header + """\ + swi #%(idname)s + movs r0, r0 + bxpl lr + b __set_syscall_errno + .fnend +""" + +arm_call_long = arm_header + """\ + .save {r4, r5, lr} + stmfd sp!, {r4, r5, lr} + ldr r4, [sp, #12] + ldr r5, [sp, #16] + swi # %(idname)s + ldmfd sp!, {r4, r5, lr} + movs r0, r0 + bxpl lr + b __set_syscall_errno + .fnend +""" + +arm_eabi_call_default = arm_header + """\ + .save {r4, r7} + stmfd sp!, {r4, r7} + ldr r7, =%(idname)s + swi #0 + ldmfd sp!, {r4, r7} + movs r0, r0 + bxpl lr + b __set_syscall_errno + .fnend +""" + +arm_eabi_call_long = arm_header + """\ + mov ip, sp + .save {r4, r5, r6, r7} + stmfd sp!, {r4, r5, r6, r7} + ldmfd ip, {r4, r5, r6} + ldr r7, =%(idname)s + swi #0 + ldmfd sp!, {r4, r5, r6, r7} + movs r0, r0 + bxpl lr + b __set_syscall_errno + .fnend +""" + +# ARM thumb assembler templates for each syscall stub +# +thumb_header = """/* autogenerated by gensyscalls.py */ + .text + .type %(fname)s, #function + .globl %(fname)s + .align 4 + .thumb_func + .fnstart + +#define __thumb__ +#include <sys/linux-syscalls.h> + + +%(fname)s: +""" + +thumb_call_default = thumb_header + """\ + .save {r7,lr} + push {r7,lr} + ldr r7, =%(idname)s + swi #0 + tst r0, r0 + bmi 1f + pop {r7,pc} +1: + neg r0, r0 + ldr r1, =__set_errno + blx r1 + pop {r7,pc} + .fnend +""" + +thumb_call_long = thumb_header + """\ + .save {r4,r5,r7,lr} + push {r4,r5,r7,lr} + ldr r4, [sp,#16] + ldr r5, [sp,#20] + ldr r7, =%(idname)s + swi #0 + tst r0, r0 + bmi 1f + pop {r4,r5,r7,pc} +1: + neg r0, r0 + ldr r1, =__set_errno + blx r1 + pop {r4,r5,r7,pc} + .fnend +""" + + +class State: + def __init__(self): + self.old_stubs = [] + self.new_stubs = [] + self.other_files = [] + self.syscalls = [] + + def x86_genstub(self,fname, numparams, idname): + t = { "fname" : fname, + "idname" : idname } + + result = x86_header % t + stack_bias = 4 + for r in range(numparams): + result += " pushl " + x86_registers[r] + "\n" + stack_bias += 4 + + for r in range(numparams): + result += " mov %d(%%esp), %s" % (stack_bias+r*4, x86_registers[r]) + "\n" + + result += x86_call % t + + for r in range(numparams): + result += " popl " + x86_registers[numparams-r-1] + "\n" + + result += x86_return + return result + + + def arm_genstub(self,fname, flags, idname): + t = { "fname" : fname, + "idname" : idname } + if flags: + numargs = int(flags) + if numargs > 4: + return arm_call_long % t + return arm_call_default % t + + + def arm_eabi_genstub(self,fname, flags, idname): + t = { "fname" : fname, + "idname" : idname } + if flags: + numargs = int(flags) + if numargs > 4: + return arm_eabi_call_long % t + return arm_eabi_call_default % t + + + def thumb_genstub(self,fname, flags, idname): + t = { "fname" : fname, + "idname" : idname } + if flags: + numargs = int(flags) + if numargs > 4: + return thumb_call_long % t + return thumb_call_default % t + + + def process_file(self,input): + parser = SysCallsTxtParser() + parser.parse_file(input) + self.syscalls = parser.syscalls + parser = None + + for t in self.syscalls: + syscall_func = t["func"] + syscall_params = t["params"] + syscall_name = t["name"] + + if t["id"] >= 0: + if gen_thumb_stubs: + t["asm-thumb"] = self.thumb_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name) + else: + if gen_eabi_stubs: + t["asm-arm"] = self.arm_eabi_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name) + else: + t["asm-arm"] = self.arm_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name) + + if t["id2"] >= 0: + t["asm-x86"] = self.x86_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name) + + def gen_NR_syscall(self,fp,name,id): + fp.write( "#define __NR_%-25s (__NR_SYSCALL_BASE + %d)\n" % (name,id) ) + + # now dump the content of linux/_syscalls.h + def gen_linux_syscalls_h(self): + path = "include/sys/linux-syscalls.h" + D( "generating "+path ) + fp = create_file( path ) + fp.write( "/* auto-generated by gensyscalls.py, do not touch */\n" ) + fp.write( "#ifndef _BIONIC_LINUX_SYSCALLS_H_\n\n" ) + fp.write( "#if !defined __ASM_ARM_UNISTD_H && !defined __ASM_I386_UNISTD_H\n" ) + fp.write( "#if defined __arm__ && !defined __ARM_EABI__ && !defined __thumb__\n" ) + fp.write( " # define __NR_SYSCALL_BASE 0x900000\n" ) + fp.write( " #else\n" ) + fp.write( " # define __NR_SYSCALL_BASE 0\n" ) + fp.write( " #endif\n\n" ) + + # first, all common syscalls + for sc in self.syscalls: + sc_id = sc["id"] + sc_id2 = sc["id2"] + sc_name = sc["name"] + if sc_id == sc_id2 and sc_id >= 0: + self.gen_NR_syscall( fp, sc_name, sc_id ) + + # now, all arm-specific syscalls + fp.write( "\n#ifdef __arm__\n" ); + for sc in self.syscalls: + sc_id = sc["id"] + sc_id2 = sc["id2"] + sc_name = sc["name"] + if sc_id != sc_id2 and sc_id >= 0: + self.gen_NR_syscall( fp, sc_name, sc_id ) + fp.write( "#endif\n" ); + + # finally, all i386-specific syscalls + fp.write( "\n#ifdef __i386__\n" ); + for sc in self.syscalls: + sc_id = sc["id"] + sc_id2 = sc["id2"] + sc_name = sc["name"] + if sc_id != sc_id2 and sc_id2 >= 0: + self.gen_NR_syscall( fp, sc_name, sc_id2 ) + fp.write( "#endif\n" ); + + fp.write( "\n#endif\n" ) + fp.write( "\n#endif /* _BIONIC_LINUX_SYSCALLS_H_ */\n" ); + fp.close() + self.other_files.append( path ) + + + # now dump the content of linux/_syscalls.h + def gen_linux_unistd_h(self): + path = "include/sys/linux-unistd.h" + D( "generating "+path ) + fp = create_file( path ) + fp.write( "/* auto-generated by gensyscalls.py, do not touch */\n" ) + fp.write( "#ifndef _BIONIC_LINUX_UNISTD_H_\n\n" ); + fp.write( "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n" ) + + for sc in self.syscalls: + fp.write( sc["decl"]+"\n" ) + + fp.write( "#ifdef __cplusplus\n}\n#endif\n" ) + fp.write( "\n#endif /* _BIONIC_LINUX_UNISTD_H_ */\n" ); + fp.close() + self.other_files.append( path ) + + # now dump the contents of syscalls.mk + def gen_arch_arm_syscalls_mk(self): + path = "arch-arm/syscalls.mk" + D( "generating "+path ) + fp = create_file( path ) + fp.write( "# auto-generated by gensyscalls.py, do not touch\n" ) + fp.write( "syscall_src := \n" ) + for sc in self.syscalls: + if sc["id"] >= 0: + fp.write( "syscall_src += arch-arm/syscalls/%s.S\n" % sc["func"] ) + fp.close() + self.other_files.append( path ) + + # now generate each syscall stub + def gen_syscall_stubs(self): + for sc in self.syscalls: + if sc.has_key("asm-arm"): + fname = "arch-arm/syscalls/%s.S" % sc["func"] + D( ">>> generating "+fname ) + fp = create_file( fname ) + fp.write(sc["asm-arm"]) + fp.close() + self.new_stubs.append( fname ) + + if sc.has_key("asm-thumb"): + fname = "arch-arm/syscalls/%s.S" % sc["func"] + D( ">>> generating "+fname ) + fp = create_file( fname ) + fp.write(sc["asm-thumb"]) + fp.close() + self.new_stubs.append( fname ) + + if sc.has_key("asm-x86"): + fname = "arch-x86/syscalls/%s.S" % sc["func"] + D( ">>> generating "+fname ) + fp = create_file( fname ) + fp.write(sc["asm-x86"]) + fp.close() + self.new_stubs.append( fname ) + + + def regenerate(self): + D( "scanning for existing architecture-specific stub files" ) + + bionic_root_len = len(bionic_root) + + for arch in all_archs: + arch_path = bionic_root + "arch-" + arch + D( "scanning " + arch_path ) + files = glob.glob( arch_path + "/syscalls/*.S" ) + for f in files: + self.old_stubs.append( f[bionic_root_len:] ) + + D( "found %d stub files" % len(self.old_stubs) ) + + if not os.path.exists( bionic_temp ): + D( "creating %s" % bionic_temp ) + os.mkdir( bionic_temp ) + +# D( "p4 editing source files" ) +# for arch in all_archs: +# commands.getoutput( "p4 edit " + arch + "/syscalls/*.S " ) +# commands.getoutput( "p4 edit " + arch + "/syscalls.mk" ) +# commands.getoutput( "p4 edit " + bionic_root + "include/sys/linux-syscalls.h" ) + + D( "re-generating stubs and support files" ) + + self.gen_linux_syscalls_h() + self.gen_arch_arm_syscalls_mk() + self.gen_linux_unistd_h() + self.gen_syscall_stubs() + + D( "comparing files" ) + adds = [] + edits = [] + + for stub in self.new_stubs + self.other_files: + if not os.path.exists( bionic_root + stub ): + # new file, P4 add it + D( "new file: " + stub) + adds.append( bionic_root + stub ) + shutil.copyfile( bionic_temp + stub, bionic_root + stub ) + + elif not filecmp.cmp( bionic_temp + stub, bionic_root + stub ): + D( "changed file: " + stub) + edits.append( stub ) + + deletes = [] + for stub in self.old_stubs: + if not stub in self.new_stubs: + D( "deleted file: " + stub) + deletes.append( bionic_root + stub ) + + + if adds: + commands.getoutput( "p4 add " + string.join( adds, " " ) ) + if deletes: + commands.getoutput( "p4 delete " + string.join( deletes, " " ) ) + if edits: + commands.getoutput( "p4 edit " + string.join( edits, " " ) ) + for file in edits: + shutil.copyfile( bionic_temp + file, bionic_root + file ) + + D("ready to go !!") + +D_setlevel(1) + +state = State() +state.process_file(bionic_root+"SYSCALLS.TXT") +state.regenerate() |