summaryrefslogtreecommitdiffstats
path: root/libc/tools/gensyscalls.py
diff options
context:
space:
mode:
Diffstat (limited to 'libc/tools/gensyscalls.py')
-rwxr-xr-xlibc/tools/gensyscalls.py451
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()