Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/python
      2 #
      3 # this tool is used to check that the syscall numbers that are in
      4 # SYSCALLS.TXT correspond to those found in the Linux kernel sources
      5 # for the arm and i386 architectures
      6 #
      7 
      8 import sys, re, string, os, commands
      9 from   bionic_utils import *
     10 
     11 # change this if necessary
     12 syscalls_txt = "SYSCALLS.TXT"
     13 
     14 def usage():
     15     print "usage: checksyscalls [options] [kernel_headers_rootdir]"
     16     print "    options:    -v   enable verbose mode"
     17     sys.exit(1)
     18 
     19 
     20 linux_root    = None
     21 syscalls_file = None
     22 
     23 def parse_command_line(args):
     24     global linux_root, syscalls_file, verbose
     25 
     26     program = args[0]
     27     args    = args[1:]
     28     while len(args) > 0 and args[0][0] == "-":
     29         option = args[0][1:]
     30         args   = args[1:]
     31 
     32         if option == "v":
     33             D_setlevel(1)
     34         else:
     35             usage()
     36 
     37     if len(args) > 2:
     38         usage()
     39 
     40     if len(args) == 0:
     41         linux_root = find_kernel_headers()
     42         if linux_root == None:
     43             print "Could not locate original or system kernel headers root directory."
     44             print "Please specify one when calling this program, i.e. 'checksyscalls <headers-directory>'"
     45             sys.exit(1)
     46         print "using the following kernel headers root: '%s'" % linux_root
     47     else:
     48         linux_root = args[0]
     49         if not os.path.isdir(linux_root):
     50             print "the directory '%s' does not exist. aborting\n" % headers_root
     51             sys.exit(1)
     52 
     53 parse_command_line(sys.argv)
     54 
     55 syscalls_file = find_file_from_upwards(None, syscalls_txt)
     56 if not syscalls_file:
     57     print "could not locate the %s file. Aborting" % syscalls_txt
     58     sys.exit(1)
     59 
     60 print "parsing %s" % syscalls_file
     61 
     62 # read the syscalls description file
     63 #
     64 
     65 parser = SysCallsTxtParser()
     66 parser.parse_file(syscalls_file)
     67 syscalls = parser.syscalls
     68 
     69 re_nr_line       = re.compile( r"#define __NR_(\w*)\s*\(__NR_SYSCALL_BASE\+\s*(\w*)\)" )
     70 re_nr_clock_line = re.compile( r"#define __NR_(\w*)\s*\(__NR_timer_create\+(\w*)\)" )
     71 re_arm_nr_line   = re.compile( r"#define __ARM_NR_(\w*)\s*\(__ARM_NR_BASE\+\s*(\w*)\)" )
     72 re_x86_line      = re.compile( r"#define __NR_(\w*)\s*([0-9]*)" )
     73 
     74 # now read the Linux arm header
     75 def process_nr_line(line,dict):
     76 
     77     m = re_nr_line.match(line)
     78     if m:
     79         dict[m.group(1)] = int(m.group(2))
     80         return
     81 
     82     m = re_nr_clock_line.match(line)
     83     if m:
     84         dict[m.group(1)] = int(m.group(2)) + 259
     85         return
     86 
     87     m = re_arm_nr_line.match(line)
     88     if m:
     89         offset_str = m.group(2)
     90         #print "%s = %s" % (m.group(1), offset_str)
     91         base = 10
     92         if offset_str.lower().startswith("0x"):
     93           # Processing something similar to
     94           #   #define __ARM_NR_cmpxchg  (__ARM_NR_BASE+0x00fff0)
     95           base = 16
     96         dict["ARM_"+m.group(1)] = int(offset_str, base) + 0x0f0000
     97         return
     98 
     99     m = re_x86_line.match(line)
    100     if m:
    101         # try block because the ARM header has some #define _NR_XXXXX  /* nothing */
    102         try:
    103             #print "%s = %s" % (m.group(1), m.group(2))
    104             dict[m.group(1)] = int(m.group(2))
    105         except:
    106             pass
    107         return
    108 
    109 
    110 def process_header(header_file,dict):
    111     fp = open(header_file)
    112     D("reading "+header_file)
    113     for line in fp.xreadlines():
    114         line = line.strip()
    115         if not line: continue
    116         process_nr_line(line,dict)
    117     fp.close()
    118 
    119 arm_dict = {}
    120 x86_dict = {}
    121 
    122 # remove trailing slash from the linux_root, if any
    123 if linux_root[-1] == '/':
    124     linux_root = linux_root[:-1]
    125 
    126 arm_unistd = find_arch_header(linux_root, "arm", "unistd.h")
    127 if not arm_unistd:
    128     print "WEIRD: Could not locate the ARM unistd.h kernel header file,"
    129     print "maybe using a different set of kernel headers might help."
    130     sys.exit(1)
    131 
    132 # on recent kernels, asm-i386 and asm-x64_64 have been merged into asm-x86
    133 # with two distinct unistd_32.h and unistd_64.h definition files.
    134 # take care of this here
    135 #
    136 x86_unistd = find_arch_header(linux_root, "i386", "unistd.h")
    137 if not x86_unistd:
    138     x86_unistd = find_arch_header(linux_root, "x86", "unistd_32.h")
    139     if not x86_unistd:
    140         print "WEIRD: Could not locate the i386/x86 unistd.h header file,"
    141         print "maybe using a different set of kernel headers might help."
    142         sys.exit(1)
    143 
    144 process_header( arm_unistd, arm_dict )
    145 process_header( x86_unistd, x86_dict )
    146 
    147 # now perform the comparison
    148 errors = 0
    149 
    150 def check_syscalls(archname, idname, arch_dict):
    151     errors = 0
    152     for sc in syscalls:
    153         sc_name = sc["name"]
    154         sc_id   = sc[idname]
    155         if sc_id >= 0:
    156             if not arch_dict.has_key(sc_name):
    157                 print "%s syscall %s not defined, should be %d !!" % (archname, sc_name, sc_id)
    158                 errors += 1
    159             elif not arch_dict.has_key(sc_name):
    160                 print "%s syscall %s is not implemented!" % (archname, sc_name)
    161                 errors += 1
    162             elif arch_dict[sc_name] != sc_id:
    163                 print "%s syscall %s should be %d instead of %d !!" % (archname, sc_name, arch_dict[sc_name], sc_id)
    164                 errors += 1
    165     return errors
    166 
    167 errors += check_syscalls("arm", "id", arm_dict)
    168 errors += check_syscalls("x86", "id2", x86_dict)
    169 
    170 if errors == 0:
    171     print "congratulations, everything's fine !!"
    172 else:
    173     print "correct %d errors !!" % errors
    174