• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 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", "sh" ]
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# SuperH assembler templates for each syscall stub
192#
193superh_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
204superh_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
2250:  .long   %(idname)s
2261:  .long   __set_syscall_errno
227"""
228
229superh_5args_header = """
230    /* get ready for additonal arg */
231    mov.l   @r15, r0
232"""
233
234superh_6args_header = """
235    /* get ready for additonal arg */
236    mov.l   @r15, r0
237    mov.l   @(4, r15), r1
238"""
239
240superh_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
248class 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
601D_setlevel(1)
602
603state = State()
604state.process_file(bionic_root+"SYSCALLS.TXT")
605state.regenerate()
606