summaryrefslogtreecommitdiffstats
path: root/libc/tools
diff options
context:
space:
mode:
Diffstat (limited to 'libc/tools')
-rw-r--r--libc/tools/bionic_utils.py306
-rwxr-xr-xlibc/tools/checksyscalls.py175
-rwxr-xr-xlibc/tools/genserv.py76
-rwxr-xr-xlibc/tools/gensyscalls.py506
4 files changed, 1063 insertions, 0 deletions
diff --git a/libc/tools/bionic_utils.py b/libc/tools/bionic_utils.py
new file mode 100644
index 0000000..65ff042
--- /dev/null
+++ b/libc/tools/bionic_utils.py
@@ -0,0 +1,306 @@
+# common python utility routines for the Bionic tool scripts
+
+import sys, os, commands, string
+
+# support Bionic architectures, add new ones as appropriate
+#
+bionic_archs = [ "arm", "x86" ]
+
+# basic debugging trace support
+# call D_setlevel to set the verbosity level
+# and D(), D2(), D3(), D4() to add traces
+#
+verbose = 1
+
+def D(msg):
+ global verbose
+ if verbose > 0:
+ print msg
+
+def D2(msg):
+ global verbose
+ if verbose >= 2:
+ print msg
+
+def D3(msg):
+ global verbose
+ if verbose >= 3:
+ print msg
+
+def D4(msg):
+ global verbose
+ if verbose >= 4:
+ print msg
+
+def D_setlevel(level):
+ global verbose
+ verbose = level
+
+
+def find_dir_of(path):
+ '''return the directory name of 'path', or "." if there is none'''
+ # remove trailing slash
+ if len(path) > 1 and path[-1] == '/':
+ path = path[:-1]
+
+ # find parent directory name
+ d = os.path.dirname(path)
+ if d == "":
+ return "."
+ else:
+ return d
+
+# other stuff
+#
+#
+def find_file_from_upwards(from_path,target_file):
+ """find a file in the current directory or its parents. if 'from_path' is None,
+ seach from the current program's directory"""
+ path = from_path
+ if path == None:
+ path = find_dir_of(sys.argv[0])
+ D("this script seems to be located in: %s" % path)
+
+ while 1:
+ if path == "":
+ path = "."
+
+ file = path + "/" + target_file
+ D("probing "+file)
+
+ if os.path.isfile(file):
+ D("found %s in %s" % (target_file, path))
+ return file
+
+ if path == ".":
+ break
+
+ path = os.path.dirname(path)
+
+ path = ""
+ while 1:
+ path = "../" + path
+ file = path + target_file
+ D("probing "+file)
+
+ if os.path.isfile(file):
+ D("found %s in %s" % (target_file, path))
+ return file
+
+
+ return None
+
+def find_bionic_root():
+ '''find the root of the Bionic source tree. we check for the SYSCALLS.TXT file
+ from the location of the current program's directory.'''
+
+ # note that we can't use find_file_from_upwards() since we can't use os.path.abspath
+ # that's because in some cases the p4 client is in a symlinked directory, and this
+ # function will return the real path instead, which later creates problems when
+ # p4 commands are issued
+ #
+ file = find_file_from_upwards(None, "SYSCALLS.TXT")
+ if file:
+ return os.path.dirname(file)
+ else:
+ return None
+
+def find_kernel_headers():
+ """try to find the directory containing the kernel headers for this machine"""
+ status, version = commands.getstatusoutput( "uname -r" ) # get Linux kernel version
+ if status != 0:
+ D("could not execute 'uname -r' command properly")
+ return None
+
+ # get rid of the "-xenU" suffix that is found in Xen virtual machines
+ if len(version) > 5 and version[-5:] == "-xenU":
+ version = version[:-5]
+
+ path = "/usr/src/linux-headers-" + version
+ D("probing %s for kernel headers" % (path+"/include"))
+ ret = os.path.isdir( path )
+ if ret:
+ D("found kernel headers in: %s" % (path + "/include"))
+ return path
+ return None
+
+
+# parser for the SYSCALLS.TXT file
+#
+class SysCallsTxtParser:
+ def __init__(self):
+ self.syscalls = []
+ self.lineno = 0
+
+ def E(msg):
+ print "%d: %s" % (self.lineno, msg)
+
+ def parse_line(self, line):
+ """ parse a syscall spec line.
+
+ line processing, format is
+ return type func_name[:syscall_name[:call_id]] ( [paramlist] ) (syscall_number[,syscall_number_x86])|stub
+ """
+ pos_lparen = line.find('(')
+ E = self.E
+ if pos_lparen < 0:
+ E("missing left parenthesis in '%s'" % line)
+ return
+
+ pos_rparen = line.rfind(')')
+ if pos_rparen < 0 or pos_rparen <= pos_lparen:
+ E("missing or misplaced right parenthesis in '%s'" % line)
+ return
+
+ return_type = line[:pos_lparen].strip().split()
+ if len(return_type) < 2:
+ E("missing return type in '%s'" % line)
+ return
+
+ syscall_func = return_type[-1]
+ return_type = string.join(return_type[:-1],' ')
+ call_id = -1
+
+ pos_colon = syscall_func.find(':')
+ if pos_colon < 0:
+ syscall_name = syscall_func
+ else:
+ if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
+ E("misplaced colon in '%s'" % line)
+ return
+
+ # now find if there is a call_id for a dispatch-type syscall
+ # after the optional 2nd colon
+ pos_colon2 = syscall_func.find(':', pos_colon + 1)
+ if pos_colon2 < 0:
+ syscall_name = syscall_func[pos_colon+1:]
+ syscall_func = syscall_func[:pos_colon]
+ else:
+ if pos_colon2+1 >= len(syscall_func):
+ E("misplaced colon2 in '%s'" % line)
+ return
+ syscall_name = syscall_func[(pos_colon+1):pos_colon2]
+ call_id = int(syscall_func[pos_colon2+1:])
+ syscall_func = syscall_func[:pos_colon]
+
+ if pos_rparen > pos_lparen+1:
+ syscall_params = line[pos_lparen+1:pos_rparen].split(',')
+ params = string.join(syscall_params,',')
+ else:
+ syscall_params = []
+ params = "void"
+
+ number = line[pos_rparen+1:].strip()
+ if number == "stub":
+ syscall_id = -1
+ syscall_id2 = -1
+ else:
+ try:
+ if number[0] == '#':
+ number = number[1:].strip()
+ numbers = string.split(number,',')
+ syscall_id = int(numbers[0])
+ syscall_id2 = syscall_id
+ if len(numbers) > 1:
+ syscall_id2 = int(numbers[1])
+ except:
+ E("invalid syscall number in '%s'" % line)
+ return
+
+ t = { "id" : syscall_id,
+ "id2" : syscall_id2,
+ "cid" : call_id,
+ "name" : syscall_name,
+ "func" : syscall_func,
+ "params" : syscall_params,
+ "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params) }
+
+ self.syscalls.append(t)
+
+ def parse_file(self, file_path):
+ D2("parse_file: %s" % file_path)
+ fp = open(file_path)
+ for line in fp.xreadlines():
+ self.lineno += 1
+ line = line.strip()
+ if not line: continue
+ if line[0] == '#': continue
+ self.parse_line(line)
+
+ fp.close()
+
+
+class Output:
+ def __init__(self,out=sys.stdout):
+ self.out = out
+
+ def write(self,msg):
+ self.out.write(msg)
+
+ def writeln(self,msg):
+ self.out.write(msg)
+ self.out.write("\n")
+
+class StringOutput:
+ def __init__(self):
+ self.line = ""
+
+ def write(self,msg):
+ self.line += msg
+ D2("write '%s'" % msg)
+
+ def writeln(self,msg):
+ self.line += msg + '\n'
+ D2("write '%s\\n'"% msg)
+
+ def get(self):
+ return self.line
+
+
+def create_file_path(path):
+ dirs = []
+ while 1:
+ parent = os.path.dirname(path)
+ if parent == "/":
+ break
+ dirs.append(parent)
+ path = parent
+
+ dirs.reverse()
+ for dir in dirs:
+ #print "dir %s" % dir
+ if os.path.isdir(dir):
+ continue
+ os.mkdir(dir)
+
+def walk_source_files(paths,callback,args,excludes=[]):
+ """recursively walk a list of paths and files, only keeping the source files in directories"""
+ for path in paths:
+ if not os.path.isdir(path):
+ callback(path,args)
+ else:
+ for root, dirs, files in os.walk(path):
+ #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes))
+ if len(excludes):
+ for d in dirs[:]:
+ if d in excludes:
+ dirs.remove(d)
+ for f in files:
+ r, ext = os.path.splitext(f)
+ if ext in [ ".h", ".c", ".cpp", ".S" ]:
+ callback( "%s/%s" % (root,f), args )
+
+def cleanup_dir(path):
+ """create a directory if needed, and ensure that it is totally empty
+ by removing any existing content in it"""
+ if not os.path.exists(path):
+ os.mkdir(path)
+ else:
+ for root, dirs, files in os.walk(path, topdown=False):
+ if root.endswith("kernel_headers/"):
+ # skip 'kernel_headers'
+ continue
+ for name in files:
+ os.remove(os.path.join(root, name))
+ for name in dirs:
+ os.rmdir(os.path.join(root, name))
diff --git a/libc/tools/checksyscalls.py b/libc/tools/checksyscalls.py
new file mode 100755
index 0000000..9edb390
--- /dev/null
+++ b/libc/tools/checksyscalls.py
@@ -0,0 +1,175 @@
+#!/usr/bin/python
+#
+# this tool is used to check that the syscall numbers that are in
+# SYSCALLS.TXT correspond to those found in the Linux kernel sources
+# for the arm and i386 architectures
+#
+
+import sys, re, string, os, commands
+from bionic_utils import *
+
+# change this if necessary
+syscalls_txt = "SYSCALLS.TXT"
+
+def usage():
+ print "usage: checksyscalls [options] [kernel_headers_rootdir]"
+ print " options: -v enable verbose mode"
+ sys.exit(1)
+
+
+linux_root = None
+syscalls_file = None
+
+def parse_command_line(args):
+ global linux_root, syscalls_file, verbose
+
+ program = args[0]
+ args = args[1:]
+ while len(args) > 0 and args[0][0] == "-":
+ option = args[0][1:]
+ args = args[1:]
+
+ if option == "v":
+ D_setlevel(1)
+ else:
+ usage()
+
+ if len(args) > 2:
+ usage()
+
+ if len(args) == 0:
+ linux_root = find_kernel_headers()
+ if linux_root == None:
+ print "could not locate this system kernel headers root directory, please"
+ print "specify one when calling this program, i.e. 'checksyscalls <headers-directory>'"
+ sys.exit(1)
+ print "using the following kernel headers root: '%s'" % linux_root
+ else:
+ linux_root = args[0]
+ if not os.path.isdir(linux_root):
+ print "the directory '%s' does not exist. aborting\n" % headers_root
+ sys.exit(1)
+
+parse_command_line(sys.argv)
+
+syscalls_file = find_file_from_upwards(None, syscalls_txt)
+if not syscalls_file:
+ print "could not locate the %s file. Aborting" % syscalls_txt
+ sys.exit(1)
+
+print "parsing %s" % syscalls_file
+
+# read the syscalls description file
+#
+
+parser = SysCallsTxtParser()
+parser.parse_file(syscalls_file)
+syscalls = parser.syscalls
+
+re_nr_line = re.compile( r"#define __NR_(\w*)\s*\(__NR_SYSCALL_BASE\+\s*(\w*)\)" )
+re_nr_clock_line = re.compile( r"#define __NR_(\w*)\s*\(__NR_timer_create\+(\w*)\)" )
+re_arm_nr_line = re.compile( r"#define __ARM_NR_(\w*)\s*\(__ARM_NR_BASE\+\s*(\w*)\)" )
+re_x86_line = re.compile( r"#define __NR_(\w*)\s*([0-9]*)" )
+
+# now read the Linux arm header
+def process_nr_line(line,dict):
+
+ m = re_nr_line.match(line)
+ if m:
+ dict[m.group(1)] = int(m.group(2))
+ return
+
+ m = re_nr_clock_line.match(line)
+ if m:
+ dict[m.group(1)] = int(m.group(2)) + 259
+ return
+
+ m = re_arm_nr_line.match(line)
+ if m:
+ #print "%s = %s" % (m.group(1), m.group(2))
+ dict["ARM_"+m.group(1)] = int(m.group(2)) + 0x0f0000
+ return
+
+ m = re_x86_line.match(line)
+ if m:
+ # try block because the ARM header has some #define _NR_XXXXX /* nothing */
+ try:
+ #print "%s = %s" % (m.group(1), m.group(2))
+ dict[m.group(1)] = int(m.group(2))
+ except:
+ pass
+ return
+
+
+def process_header(header_file,dict):
+ fp = open(header_file)
+ D("reading "+header_file)
+ for line in fp.xreadlines():
+ line = line.strip()
+ if not line: continue
+ process_nr_line(line,dict)
+ fp.close()
+
+arm_dict = {}
+x86_dict = {}
+
+
+# remove trailing slash and '/include' from the linux_root, if any
+if linux_root[-1] == '/':
+ linux_root = linux_root[:-1]
+
+if len(linux_root) > 8 and linux_root[-8:] == '/include':
+ linux_root = linux_root[:-8]
+
+arm_unistd = linux_root + "/include/asm-arm/unistd.h"
+if not os.path.exists(arm_unistd):
+ print "WEIRD: could not locate the ARM unistd.h header file"
+ print "tried searching in '%s'" % arm_unistd
+ print "maybe using a different set of kernel headers might help"
+ sys.exit(1)
+
+# on recent kernels, asm-i386 and asm-x64_64 have been merged into asm-x86
+# with two distinct unistd_32.h and unistd_64.h definition files.
+# take care of this here
+#
+x86_unistd = linux_root + "/include/asm-i386/unistd.h"
+if not os.path.exists(x86_unistd):
+ x86_unistd1 = x86_unistd
+ x86_unistd = linux_root + "/include/asm-x86/unistd_32.h"
+ if not os.path.exists(x86_unistd):
+ print "WEIRD: could not locate the i386/x86 unistd.h header file"
+ print "tried searching in '%s' and '%s'" % (x86_unistd1, x86_unistd)
+ print "maybe using a different set of kernel headers might help"
+ sys.exit(1)
+
+process_header( linux_root+"/include/asm-arm/unistd.h", arm_dict )
+process_header( x86_unistd, x86_dict )
+
+# now perform the comparison
+errors = 0
+for sc in syscalls:
+ sc_name = sc["name"]
+ sc_id = sc["id"]
+ if sc_id >= 0:
+ if not arm_dict.has_key(sc_name):
+ print "arm syscall %s not defined !!" % sc_name
+ errors += 1
+ elif arm_dict[sc_name] != sc_id:
+ print "arm syscall %s should be %d instead of %d !!" % (sc_name, arm_dict[sc_name], sc_id)
+ errors += 1
+
+for sc in syscalls:
+ sc_name = sc["name"]
+ sc_id2 = sc["id2"]
+ if sc_id2 >= 0:
+ if not x86_dict.has_key(sc_name):
+ print "x86 syscall %s not defined !!" % sc_name
+ errors += 1
+ elif x86_dict[sc_name] != sc_id2:
+ print "x86 syscall %s should be %d instead of %d !!" % (sc_name, x86_dict[sc_name], sc_id2)
+ errors += 1
+
+if errors == 0:
+ print "congratulations, everything's fine !!"
+else:
+ print "correct %d errors !!" % errors
diff --git a/libc/tools/genserv.py b/libc/tools/genserv.py
new file mode 100755
index 0000000..e37d28f
--- /dev/null
+++ b/libc/tools/genserv.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#
+
+import sys, os, string, re
+
+def usage():
+ print """\
+ usage: genserv < /etc/services > netbsd/net/services.h
+
+ this program is used to generate the hard-coded internet service list for the
+ Bionic C library.
+"""
+
+re_service = re.compile(r"([\d\w\-_]+)\s+(\d+)/(tcp|udp)(.*)")
+re_alias = re.compile(r"([\d\w\-_]+)(.*)")
+
+class Service:
+ def __init__(self,name,port,proto):
+ self.name = name
+ self.port = port
+ self.proto = proto
+ self.aliases = []
+
+ def add_alias(self,alias):
+ self.aliases.append(alias)
+
+ def __str__(self):
+ result = "\\%0o%s" % (len(self.name),self.name)
+ result += "\\%0o\\%0o" % (((self.port >> 8) & 255), self.port & 255)
+ if self.proto == "tcp":
+ result += "t"
+ else:
+ result += "u"
+
+ result += "\\%0o" % len(self.aliases)
+ for alias in self.aliases:
+ result += "\\%0o%s" % (len(alias), alias)
+
+ return result
+
+def parse(f):
+ result = [] # list of Service objects
+ for line in f.xreadlines():
+ if len(line) > 0 and line[-1] == "\n":
+ line = line[:-1]
+ if len(line) > 0 and line[-1] == "\r":
+ line = line[:-1]
+
+ line = string.strip(line)
+ if len(line) == 0 or line[0] == "#":
+ continue
+
+ m = re_service.match(line)
+ if m:
+ service = Service( m.group(1), int(m.group(2)), m.group(3) )
+ rest = string.strip(m.group(4))
+
+ while 1:
+ m = re_alias.match(rest)
+ if not m:
+ break
+ service.add_alias(m.group(1))
+ rest = string.strip(m.group(2))
+
+ result.append(service)
+
+ return result
+
+services = parse(sys.stdin)
+line = '/* generated by genserv.py - do not edit */\nstatic const char _services[] = "\\\n'
+for s in services:
+ line += str(s)+"\\\n"
+line += '\\0";\n'
+print line
+
+
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
new file mode 100755
index 0000000..530e565
--- /dev/null
+++ b/libc/tools/gensyscalls.py
@@ -0,0 +1,506 @@
+#!/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, 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 x86_genstub_cid(self, fname, numparams, idname, cid):
+ # We'll ignore numparams here because in reality, if there is a
+ # dispatch call (like a socketcall syscall) there are actually
+ # only 2 arguments to the syscall and 2 regs we have to save:
+ # %ebx <--- Argument 1 - The call id of the needed vectored
+ # syscall (socket, bind, recv, etc)
+ # %ecx <--- Argument 2 - Pointer to the rest of the arguments
+ # from the original function called (socket())
+ t = { "fname" : fname,
+ "idname" : idname }
+
+ result = x86_header % t
+ stack_bias = 4
+
+ # save the regs we need
+ result += " pushl %ebx" + "\n"
+ stack_bias += 4
+ result += " pushl %ecx" + "\n"
+ stack_bias += 4
+
+ # set the call id (%ebx)
+ result += " mov $%d, %%ebx" % (cid) + "\n"
+
+ # set the pointer to the rest of the args into %ecx
+ result += " mov %esp, %ecx" + "\n"
+ result += " addl $%d, %%ecx" % (stack_bias) + "\n"
+
+ # now do the syscall code itself
+ result += x86_call % t
+
+ # now restore the saved regs
+ result += " popl %ecx" + "\n"
+ result += " popl %ebx" + "\n"
+
+ # epilog
+ 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:
+ if t["cid"] >= 0:
+ t["asm-x86"] = self.x86_genstub_cid(syscall_func, len(syscall_params), "__NR_"+syscall_name, t["cid"])
+ else:
+ t["asm-x86"] = self.x86_genstub(syscall_func,len(syscall_params),"__NR_"+syscall_name)
+ elif t["cid"] >= 0:
+ E("cid for dispatch syscalls is only supported for x86 in "
+ "'%s'" % syscall_name)
+ return
+
+
+ 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" );
+
+ gen_syscalls = {}
+ # 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 and sc_name not in gen_syscalls:
+ self.gen_NR_syscall( fp, sc_name, sc_id2 )
+ gen_syscalls[sc_name] = True
+ 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_syscalls_mk(self, arch):
+ path = "arch-%s/syscalls.mk" % arch
+ D( "generating "+path )
+ fp = create_file( path )
+ fp.write( "# auto-generated by gensyscalls.py, do not touch\n" )
+ fp.write( "syscall_src := \n" )
+ arch_test = {
+ "arm": lambda x: x.has_key("asm-arm") or x.has_key("asm-thumb"),
+ "x86": lambda x: x.has_key("asm-x86")
+ }
+
+ for sc in self.syscalls:
+ if arch_test[arch](sc):
+ fp.write("syscall_src += arch-%s/syscalls/%s.S\n" %
+ (arch, 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") and 'arm' in all_archs:
+ 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") and 'arm' in all_archs:
+ 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") and 'x86' in all_archs:
+ 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()
+ for arch in all_archs:
+ self.gen_arch_syscalls_mk(arch)
+ 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 " + " ".join(adds))
+ if deletes:
+ commands.getoutput("p4 delete " + " ".join(deletes))
+ if edits:
+ commands.getoutput("p4 edit " +
+ " ".join((bionic_root + file) for file in 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()