| #!/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, i386 and mips 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 original or system kernel headers root directory." |
| print "Please 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]*)" ) |
| re_mips_line = re.compile( r"#define __NR_(\w*)\s*\(__NR_Linux\s*\+\s*([0-9]*)\)" ) |
| |
| # now read the Linux arm header |
| def process_nr_line(line,dict): |
| |
| m = re_mips_line.match(line) |
| if m: |
| if dict["Linux"]==4000: |
| dict[m.group(1)] = int(m.group(2)) |
| return |
| |
| 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: |
| offset_str = m.group(2) |
| #print "%s = %s" % (m.group(1), offset_str) |
| base = 10 |
| if offset_str.lower().startswith("0x"): |
| # Processing something similar to |
| # #define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0) |
| base = 16 |
| dict["ARM_"+m.group(1)] = int(offset_str, base) + 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 = {} |
| mips_dict = {} |
| |
| # remove trailing slash from the linux_root, if any |
| if linux_root[-1] == '/': |
| linux_root = linux_root[:-1] |
| |
| arm_unistd = find_arch_header(linux_root, "arm", "unistd.h") |
| if not arm_unistd: |
| print "WEIRD: Could not locate the ARM unistd.h kernel header file," |
| 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 = find_arch_header(linux_root, "i386", "unistd.h") |
| if not x86_unistd: |
| x86_unistd = find_arch_header(linux_root, "x86", "unistd_32.h") |
| if not x86_unistd: |
| print "WEIRD: Could not locate the i386/x86 unistd.h header file," |
| print "maybe using a different set of kernel headers might help." |
| sys.exit(1) |
| |
| mips_unistd = find_arch_header(linux_root, "mips", "unistd.h") |
| if not mips_unistd: |
| print "WEIRD: Could not locate the Mips unistd.h kernel header file," |
| print "maybe using a different set of kernel headers might help." |
| sys.exit(1) |
| |
| process_header( arm_unistd, arm_dict ) |
| process_header( x86_unistd, x86_dict ) |
| process_header( mips_unistd, mips_dict ) |
| |
| # now perform the comparison |
| errors = 0 |
| |
| def check_syscalls(archname, idname, arch_dict): |
| errors = 0 |
| for sc in syscalls: |
| sc_name = sc["name"] |
| sc_id = sc[idname] |
| if sc_id == -1: |
| sc_id = sc["common"] |
| if sc_id >= 0: |
| if not arch_dict.has_key(sc_name): |
| print "error: %s syscall %s not defined, should be %d" % (archname, sc_name, sc_id) |
| errors += 1 |
| elif arch_dict[sc_name] != sc_id: |
| print "error: %s syscall %s should be %d instead of %d" % (archname, sc_name, arch_dict[sc_name], sc_id) |
| errors += 1 |
| return errors |
| |
| errors += check_syscalls("arm", "armid", arm_dict) |
| errors += check_syscalls("x86", "x86id", x86_dict) |
| errors += check_syscalls("mips", "mipsid", mips_dict) |
| |
| if errors == 0: |
| print "congratulations, everything's fine !!" |
| else: |
| print "correct %d errors !!" % errors |