Home | History | Annotate | Download | only in tools
      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 
      8 import sys, os.path, glob, re, commands, filecmp, shutil
      9 
     10 from bionic_utils import *
     11 
     12 # set this to 1 if you want to generate thumb stubs
     13 gen_thumb_stubs = 0
     14 
     15 # set this to 1 if you want to generate ARM EABI stubs
     16 gen_eabi_stubs = 1
     17 
     18 # get the root Bionic directory, simply this script's dirname
     19 #
     20 bionic_root = find_bionic_root()
     21 if not bionic_root:
     22     print "could not find the Bionic root directory. aborting"
     23     sys.exit(1)
     24 
     25 if bionic_root[-1] != '/':
     26     bionic_root += "/"
     27 
     28 print "bionic_root is %s" % bionic_root
     29 
     30 # temp directory where we store all intermediate files
     31 bionic_temp = "/tmp/bionic_gensyscalls/"
     32 
     33 # all architectures, update as you see fit
     34 all_archs = [ "arm", "x86", "sh" ]
     35 
     36 def 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 
     43 def 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 
     51 x86_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 
     62 x86_registers = [ "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp" ]
     63 
     64 x86_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
     73 1:
     74 """
     75 
     76 x86_return = """    ret
     77 """
     78 
     79 # ARM assembler templates for each syscall stub
     80 #
     81 arm_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 
     93 arm_call_default = arm_header + """\
     94     swi   #%(idname)s
     95     movs    r0, r0
     96     bxpl    lr
     97     b       __set_syscall_errno
     98     .fnend
     99 """
    100 
    101 arm_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 
    114 arm_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 
    126 arm_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 #
    142 thumb_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 
    157 thumb_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}
    165 1:
    166     neg     r0, r0
    167     ldr     r1, =__set_errno
    168     blx     r1
    169     pop     {r7,pc}
    170     .fnend
    171 """
    172 
    173 thumb_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}
    183 1:
    184     neg    r0, r0
    185     ldr    r1, =__set_errno
    186     blx    r1
    187     pop    {r4,r5,r7,pc}
    188     .fnend
    189 """
    190 
    191 # SuperH assembler templates for each syscall stub
    192 #
    193 superh_header = """/* autogenerated by gensyscalls.py */
    194 #include <sys/linux-syscalls.h>
    195 
    196     .text
    197     .type %(fname)s, @function
    198     .globl %(fname)s
    199     .align 4
    200 
    201 %(fname)s:
    202 """
    203 
    204 superh_call_default = """
    205     /* invoke trap */
    206     mov.l   0f, r3  /* trap num */
    207     trapa   #(%(numargs)s + 0x10)
    208 
    209     /* check return value */
    210     cmp/pz  r0
    211     bt      %(idname)s_end
    212 
    213     /* keep error number */
    214     sts.l   pr, @-r15
    215     mov.l   1f, r1
    216     jsr     @r1
    217     mov     r0, r4
    218     lds.l   @r15+, pr
    219 
    220 %(idname)s_end:
    221     rts
    222     nop
    223 
    224     .align  2
    225 0:  .long   %(idname)s
    226 1:  .long   __set_syscall_errno
    227 """
    228 
    229 superh_5args_header = """
    230     /* get ready for additonal arg */
    231     mov.l   @r15, r0
    232 """
    233 
    234 superh_6args_header = """
    235     /* get ready for additonal arg */
    236     mov.l   @r15, r0
    237     mov.l   @(4, r15), r1
    238 """
    239 
    240 superh_7args_header = """
    241     /* get ready for additonal arg */
    242     mov.l   @r15, r0
    243     mov.l   @(4, r15), r1
    244     mov.l   @(8, r15), r2
    245 """
    246 
    247 
    248 class State:
    249     def __init__(self):
    250         self.old_stubs = []
    251         self.new_stubs = []
    252         self.other_files = []
    253         self.syscalls = []
    254 
    255     def x86_genstub(self, fname, numparams, idname):
    256         t = { "fname"  : fname,
    257               "idname" : idname }
    258 
    259         result     = x86_header % t
    260         stack_bias = 4
    261         for r in range(numparams):
    262             result     += "    pushl   " + x86_registers[r] + "\n"
    263             stack_bias += 4
    264 
    265         for r in range(numparams):
    266             result += "    mov     %d(%%esp), %s" % (stack_bias+r*4, x86_registers[r]) + "\n"
    267 
    268         result += x86_call % t
    269 
    270         for r in range(numparams):
    271             result += "    popl    " + x86_registers[numparams-r-1] + "\n"
    272 
    273         result += x86_return
    274         return result
    275 
    276     def x86_genstub_cid(self, fname, numparams, idname, cid):
    277         # We'll ignore numparams here because in reality, if there is a
    278         # dispatch call (like a socketcall syscall) there are actually
    279         # only 2 arguments to the syscall and 2 regs we have to save:
    280         #   %ebx <--- Argument 1 - The call id of the needed vectored
    281         #                          syscall (socket, bind, recv, etc)
    282         #   %ecx <--- Argument 2 - Pointer to the rest of the arguments
    283         #                          from the original function called (socket())
    284         t = { "fname"  : fname,
    285               "idname" : idname }
    286 
    287         result = x86_header % t
    288         stack_bias = 4
    289 
    290         # save the regs we need
    291         result += "    pushl   %ebx" + "\n"
    292         stack_bias += 4
    293         result += "    pushl   %ecx" + "\n"
    294         stack_bias += 4
    295 
    296         # set the call id (%ebx)
    297         result += "    mov     $%d, %%ebx" % (cid) + "\n"
    298 
    299         # set the pointer to the rest of the args into %ecx
    300         result += "    mov     %esp, %ecx" + "\n"
    301         result += "    addl    $%d, %%ecx" % (stack_bias) + "\n"
    302 
    303         # now do the syscall code itself
    304         result += x86_call % t
    305 
    306         # now restore the saved regs
    307         result += "    popl    %ecx" + "\n"
    308         result += "    popl    %ebx" + "\n"
    309 
    310         # epilog
    311         result += x86_return
    312         return result
    313 
    314     def arm_genstub(self,fname, flags, idname):
    315         t = { "fname"  : fname,
    316               "idname" : idname }
    317         if flags:
    318             numargs = int(flags)
    319             if numargs > 4:
    320                 return arm_call_long % t
    321         return arm_call_default % t
    322 
    323 
    324     def arm_eabi_genstub(self,fname, flags, idname):
    325         t = { "fname"  : fname,
    326               "idname" : idname }
    327         if flags:
    328             numargs = int(flags)
    329             if numargs > 4:
    330                 return arm_eabi_call_long % t
    331         return arm_eabi_call_default % t
    332 
    333 
    334     def thumb_genstub(self,fname, flags, idname):
    335         t = { "fname"  : fname,
    336               "idname" : idname }
    337         if flags:
    338             numargs = int(flags)
    339             if numargs > 4:
    340                 return thumb_call_long % t
    341         return thumb_call_default % t
    342 
    343 
    344     def superh_genstub(self, fname, flags, idname):
    345         numargs = int(flags)
    346         t = { "fname"  : fname,
    347               "idname" : idname,
    348               "numargs" : numargs }
    349         superh_call = superh_header
    350         if flags:
    351             if numargs == 5:
    352                 superh_call += superh_5args_header
    353             if numargs == 6:
    354                 superh_call += superh_6args_header
    355             if numargs == 7:
    356                 superh_call += superh_7args_header
    357         superh_call += superh_call_default
    358         return superh_call % t
    359 
    360 
    361     def process_file(self,input):
    362         parser = SysCallsTxtParser()
    363         parser.parse_file(input)
    364         self.syscalls = parser.syscalls
    365         parser = None
    366 
    367         for t in self.syscalls:
    368             syscall_func   = t["func"]
    369             syscall_params = t["params"]
    370             syscall_name   = t["name"]
    371 
    372             if t["id"] >= 0:
    373                 if gen_thumb_stubs:
    374                     t["asm-thumb"] = self.thumb_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
    375                 else:
    376                     if gen_eabi_stubs:
    377                         t["asm-arm"]   = self.arm_eabi_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
    378                     else:
    379                         t["asm-arm"]   = self.arm_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
    380 
    381             if t["id2"] >= 0:
    382                 if t["cid"] >= 0:
    383                     t["asm-x86"] = self.x86_genstub_cid(syscall_func, len(syscall_params), "__NR_"+syscall_name, t["cid"])
    384                 else:
    385                     t["asm-x86"] = self.x86_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
    386             elif t["cid"] >= 0:
    387                 E("cid for dispatch syscalls is only supported for x86 in "
    388                   "'%s'" % syscall_name)
    389                 return
    390             if t["id3"] >= 0:
    391                 t["asm-sh"] = self.superh_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
    392 
    393 
    394 
    395     def gen_NR_syscall(self,fp,name,id):
    396         fp.write( "#define __NR_%-25s    (__NR_SYSCALL_BASE + %d)\n" % (name,id) )
    397 
    398     # now dump the content of linux/_syscalls.h
    399     def gen_linux_syscalls_h(self):
    400         path = "include/sys/linux-syscalls.h"
    401         D( "generating "+path )
    402         fp = create_file( path )
    403         fp.write( "/* auto-generated by gensyscalls.py, do not touch */\n" )
    404         fp.write( "#ifndef _BIONIC_LINUX_SYSCALLS_H_\n\n" )
    405         fp.write( "#if !defined __ASM_ARM_UNISTD_H && !defined __ASM_I386_UNISTD_H\n" )
    406         fp.write( "#if defined __arm__ && !defined __ARM_EABI__ && !defined __thumb__\n" )
    407         fp.write( "  #  define __NR_SYSCALL_BASE  0x900000\n" )
    408         fp.write( "  #else\n" )
    409         fp.write( "  #  define  __NR_SYSCALL_BASE  0\n" )
    410         fp.write( "  #endif\n\n" )
    411 
    412         # first, all common syscalls
    413         for sc in self.syscalls:
    414             sc_id  = sc["id"]
    415             sc_id2 = sc["id2"]
    416             sc_name = sc["name"]
    417             if sc_id == sc_id2 and sc_id >= 0:
    418                 self.gen_NR_syscall( fp, sc_name, sc_id )
    419 
    420         # now, all arm-specific syscalls
    421         fp.write( "\n#ifdef __arm__\n" );
    422         for sc in self.syscalls:
    423             sc_id  = sc["id"]
    424             sc_id2 = sc["id2"]
    425             sc_name = sc["name"]
    426             if sc_id != sc_id2 and sc_id >= 0:
    427                 self.gen_NR_syscall( fp, sc_name, sc_id )
    428         fp.write( "#endif\n" );
    429 
    430         gen_syscalls = {}
    431         # finally, all i386-specific syscalls
    432         fp.write( "\n#ifdef __i386__\n" );
    433         for sc in self.syscalls:
    434             sc_id  = sc["id"]
    435             sc_id2 = sc["id2"]
    436             sc_name = sc["name"]
    437             if sc_id != sc_id2 and sc_id2 >= 0 and sc_name not in gen_syscalls:
    438                 self.gen_NR_syscall( fp, sc_name, sc_id2 )
    439                 gen_syscalls[sc_name] = True
    440         fp.write( "#endif\n" );
    441 
    442         # all superh-specific syscalls
    443         fp.write( "\n#if defined(__SH3__) || defined(__SH4__) \n" );
    444         for sc in self.syscalls:
    445             sc_id  = sc["id"]
    446             sc_id2 = sc["id2"]
    447             sc_id3 = sc["id3"]
    448             sc_name = sc["name"]
    449             if sc_id2 != sc_id3 and sc_id3 >= 0:
    450                 self.gen_NR_syscall( fp, sc_name, sc_id3 )
    451             else:
    452                 if sc_id != sc_id2 and sc_id2 >= 0:
    453                     self.gen_NR_syscall( fp, sc_name, sc_id2 )
    454         fp.write( "#endif\n" );
    455 
    456         fp.write( "\n#endif\n" )
    457         fp.write( "\n#endif /* _BIONIC_LINUX_SYSCALLS_H_ */\n" );
    458         fp.close()
    459         self.other_files.append( path )
    460 
    461 
    462     # now dump the content of linux/_syscalls.h
    463     def gen_linux_unistd_h(self):
    464         path = "include/sys/linux-unistd.h"
    465         D( "generating "+path )
    466         fp = create_file( path )
    467         fp.write( "/* auto-generated by gensyscalls.py, do not touch */\n" )
    468         fp.write( "#ifndef _BIONIC_LINUX_UNISTD_H_\n\n" );
    469         fp.write( "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n" )
    470 
    471         for sc in self.syscalls:
    472             fp.write( sc["decl"]+"\n" )
    473 
    474         fp.write( "#ifdef __cplusplus\n}\n#endif\n" )
    475         fp.write( "\n#endif /* _BIONIC_LINUX_UNISTD_H_ */\n" );
    476         fp.close()
    477         self.other_files.append( path )
    478 
    479     # now dump the contents of syscalls.mk
    480     def gen_arch_syscalls_mk(self, arch):
    481         path = "arch-%s/syscalls.mk" % arch
    482         D( "generating "+path )
    483         fp = create_file( path )
    484         fp.write( "# auto-generated by gensyscalls.py, do not touch\n" )
    485         fp.write( "syscall_src := \n" )
    486         arch_test = {
    487             "arm": lambda x: x.has_key("asm-arm") or x.has_key("asm-thumb"),
    488             "x86": lambda x: x.has_key("asm-x86"),
    489             "sh": lambda x: x.has_key("asm-sh")
    490         }
    491 
    492         for sc in self.syscalls:
    493             if arch_test[arch](sc):
    494                 fp.write("syscall_src += arch-%s/syscalls/%s.S\n" %
    495                          (arch, sc["func"]))
    496         fp.close()
    497         self.other_files.append( path )
    498 
    499     # now generate each syscall stub
    500     def gen_syscall_stubs(self):
    501         for sc in self.syscalls:
    502             if sc.has_key("asm-arm") and 'arm' in all_archs:
    503                 fname = "arch-arm/syscalls/%s.S" % sc["func"]
    504                 D( ">>> generating "+fname )
    505                 fp = create_file( fname )
    506                 fp.write(sc["asm-arm"])
    507                 fp.close()
    508                 self.new_stubs.append( fname )
    509 
    510             if sc.has_key("asm-thumb") and 'arm' in all_archs:
    511                 fname = "arch-arm/syscalls/%s.S" % sc["func"]
    512                 D( ">>> generating "+fname )
    513                 fp = create_file( fname )
    514                 fp.write(sc["asm-thumb"])
    515                 fp.close()
    516                 self.new_stubs.append( fname )
    517 
    518             if sc.has_key("asm-x86") and 'x86' in all_archs:
    519                 fname = "arch-x86/syscalls/%s.S" % sc["func"]
    520                 D( ">>> generating "+fname )
    521                 fp = create_file( fname )
    522                 fp.write(sc["asm-x86"])
    523                 fp.close()
    524                 self.new_stubs.append( fname )
    525 
    526             if sc.has_key("asm-sh"):
    527                 fname = "arch-sh/syscalls/%s.S" % sc["func"]
    528                 D( ">>> generating "+fname )
    529                 fp = create_file( fname )
    530                 fp.write(sc["asm-sh"])
    531                 fp.close()
    532                 self.new_stubs.append( fname )
    533 
    534 
    535     def  regenerate(self):
    536         D( "scanning for existing architecture-specific stub files" )
    537 
    538         bionic_root_len = len(bionic_root)
    539 
    540         for arch in all_archs:
    541             arch_path = bionic_root + "arch-" + arch
    542             D( "scanning " + arch_path )
    543             files = glob.glob( arch_path + "/syscalls/*.S" )
    544             for f in files:
    545                 self.old_stubs.append( f[bionic_root_len:] )
    546 
    547         D( "found %d stub files" % len(self.old_stubs) )
    548 
    549         if not os.path.exists( bionic_temp ):
    550             D( "creating %s" % bionic_temp )
    551             os.mkdir( bionic_temp )
    552 
    553 #        D( "p4 editing source files" )
    554 #        for arch in all_archs:
    555 #            commands.getoutput( "p4 edit " + arch + "/syscalls/*.S " )
    556 #            commands.getoutput( "p4 edit " + arch + "/syscalls.mk" )
    557 #        commands.getoutput( "p4 edit " + bionic_root + "include/sys/linux-syscalls.h" )
    558 
    559         D( "re-generating stubs and support files" )
    560 
    561         self.gen_linux_syscalls_h()
    562         for arch in all_archs:
    563             self.gen_arch_syscalls_mk(arch)
    564         self.gen_linux_unistd_h()
    565         self.gen_syscall_stubs()
    566 
    567         D( "comparing files" )
    568         adds    = []
    569         edits   = []
    570 
    571         for stub in self.new_stubs + self.other_files:
    572             if not os.path.exists( bionic_root + stub ):
    573                 # new file, P4 add it
    574                 D( "new file:     " + stub)
    575                 adds.append( bionic_root + stub )
    576                 shutil.copyfile( bionic_temp + stub, bionic_root + stub )
    577 
    578             elif not filecmp.cmp( bionic_temp + stub, bionic_root + stub ):
    579                 D( "changed file: " + stub)
    580                 edits.append( stub )
    581 
    582         deletes = []
    583         for stub in self.old_stubs:
    584             if not stub in self.new_stubs:
    585                 D( "deleted file: " + stub)
    586                 deletes.append( bionic_root + stub )
    587 
    588 
    589         if adds:
    590             commands.getoutput("p4 add " + " ".join(adds))
    591         if deletes:
    592             commands.getoutput("p4 delete " + " ".join(deletes))
    593         if edits:
    594             commands.getoutput("p4 edit " +
    595                                " ".join((bionic_root + file) for file in edits))
    596             for file in edits:
    597                 shutil.copyfile( bionic_temp + file, bionic_root + file )
    598 
    599         D("ready to go !!")
    600 
    601 D_setlevel(1)
    602 
    603 state = State()
    604 state.process_file(bionic_root+"SYSCALLS.TXT")
    605 state.regenerate()
    606