Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/python
      2 #
      3 # Copyright 2017 - The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #     http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 #
     17 
     18 """Generates a report on CKI syscall coverage in VTS LTP.
     19 
     20 This module generates a report on the syscalls in the Android CKI and
     21 their coverage in VTS LTP.
     22 
     23 The coverage report provides, for each syscall in the CKI, the number of
     24 enabled and disabled LTP tests for the syscall in VTS. If VTS test output is
     25 supplied, the report instead provides the number of disabled, skipped, failing,
     26 and passing tests for each syscall.
     27 
     28 Assumptions are made about the structure of files in LTP source
     29 and the naming convention.
     30 """
     31 
     32 import argparse
     33 import os.path
     34 import re
     35 import sys
     36 import xml.etree.ElementTree as ET
     37 import subprocess
     38 
     39 if "ANDROID_BUILD_TOP" not in os.environ:
     40   print ("Please set up your Android build environment by running "
     41          "\". build/envsetup.sh\" and \"lunch\".")
     42   sys.exit(-1)
     43 
     44 sys.path.append(os.path.join(os.environ["ANDROID_BUILD_TOP"],
     45                 "bionic/libc/tools"))
     46 import gensyscalls
     47 
     48 sys.path.append(os.path.join(os.environ["ANDROID_BUILD_TOP"],
     49                              "test/vts-testcase/kernel/ltp/configs"))
     50 import disabled_tests as vts_disabled
     51 import stable_tests as vts_stable
     52 
     53 bionic_libc_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc")
     54 
     55 src_url_start = 'https://git.kernel.org/pub/scm/linux/kernel/git/'
     56 tip_url = 'torvalds/linux.git/plain/'
     57 stable_url = 'stable/linux.git/plain/'
     58 unistd_h = 'include/uapi/asm-generic/unistd.h'
     59 arm64_unistd32_h = 'arch/arm64/include/asm/unistd32.h'
     60 arm_syscall_tbl = 'arch/arm/tools/syscall.tbl'
     61 x86_syscall_tbl = 'arch/x86/entry/syscalls/syscall_32.tbl'
     62 x86_64_syscall_tbl = 'arch/x86/entry/syscalls/syscall_64.tbl'
     63 
     64 unistd_h_url = src_url_start
     65 arm64_unistd32_h_url = src_url_start
     66 arm_syscall_tbl_url = src_url_start
     67 x86_syscall_tbl_url = src_url_start
     68 x86_64_syscall_tbl_url = src_url_start
     69 
     70 # Syscalls which are either banned, optional, or deprecated, so not part of the
     71 # CKI.
     72 CKI_BLACKLIST = [
     73         'acct',                    # CONFIG_BSD_PROCESS_ACCT
     74         'fanotify_init',           # CONFIG_FANOTIFY
     75         'fanotify_mark',           # CONFIG_FANOTIFY
     76         'get_mempolicy',           # CONFIG_NUMA
     77         'init_module',             # b/112470257 (use finit_module)
     78         'ipc',                     # CONFIG_SYSVIPC
     79         'kcmp',                    # CONFIG_CHECKPOINT_RESTORE
     80         'kexec_file_load',         # CONFIG_EXEC_FILE
     81         'kexec_load',              # CONFIG_KEXEC
     82         'lookup_dcookie',          # b/112474343 (requires kernel module)
     83         'mbind',                   # CONFIG_NUMA
     84         'membarrier',              # CONFIG_MEMBARRIER
     85         'migrate_pages',           # CONFIG_NUMA
     86         'move_pages',              # CONFIG_MIGRATION
     87         'mq_getsetattr',           # CONFIG_POSIX_MQUEUE
     88         'mq_notify',               # CONFIG_POSIX_MQUEUE
     89         'mq_open',                 # CONFIG_POSIX_MQUEUE
     90         'mq_timedreceive',         # CONFIG_POSIX_MQUEUE
     91         'mq_timedsend',            # CONFIG_POSIX_MQUEUE
     92         'mq_unlink',               # CONFIG_POSIX_MQUEUE
     93         'msgctl',                  # CONFIG_SYSVIPC
     94         'msgget',                  # CONFIG_SYSVIPC
     95         'msgrcv',                  # CONFIG_SYSVIPC
     96         'msgsnd',                  # CONFIG_SYSVIPC
     97         'name_to_handle_at',       # CONFIG_FHANDLE
     98         'nfsservctl',              # not present after 3.1
     99         'open_by_handle_at',       # CONFIG_FHANDLE
    100         'pciconfig_iobase',        # not present for arm/x86
    101         'pciconfig_read',          # CONFIG_PCI_SYSCALL
    102         'pciconfig_write',         # CONFIG_PCI_SYSCALL
    103         'pkey_alloc',              # CONFIG_MMU, added in 4.9
    104         'pkey_free',               # CONFIG_MMU, added in 4.9
    105         'pkey_mprotect',           # CONFIG_MMU, added in 4.9
    106         'rseq',                    # CONFIG_RSEQ
    107         'semctl',                  # CONFIG_SYSVIPC
    108         'semget',                  # CONFIG_SYSVIPC
    109         'semop',                   # CONFIG_SYSVIPC
    110         'semtimedop',              # CONFIG_SYSVIPC
    111         'set_mempolicy',           # CONFIG_NUMA
    112         'sgetmask',                # CONFIG_SGETMASK_SYSCALL
    113         'shmat',                   # CONFIG_SYSVIPC
    114         'shmctl',                  # CONFIG_SYSVIPC
    115         'shmdt',                   # CONFIG_SYSVIPC
    116         'shmget',                  # CONFIG_SYSVIPC
    117         'ssetmask',                # CONFIG_SGETMASK_SYSCALL
    118         'stime',                   # deprecated
    119         'syscall',                 # deprecated
    120         '_sysctl',                 # CONFIG_SYSCTL_SYSCALL
    121         'sysfs',                   # CONFIG_SYSFS_SYSCALL
    122         'uselib',                  # CONFIG_USELIB
    123         'userfaultfd',             # CONFIG_USERFAULTFD
    124         'vm86',                    # CONFIG_X86_LEGACY_VM86
    125         'vm86old',                 # CONFIG_X86_LEGACY_VM86
    126         'vserver',                 # deprecated
    127 ]
    128 
    129 EXTERNAL_TESTS = [ ("bpf", "libbpf_android/BpfLoadTest.cpp"),
    130                    ("bpf", "libbpf_android/BpfMapTest.cpp"),
    131                    ("bpf", "netd/libbpf/BpfMapTest.cpp"),
    132                    ("bpf", "api/bpf_native_test/BpfTest.cpp"),
    133                    ("clock_adjtime", "kselftest/timers/valid-adjtimex.c"),
    134                    ("seccomp", "kselftest/seccomp_bpf")
    135                  ]
    136 
    137 class CKI_Coverage(object):
    138   """Determines current test coverage of CKI system calls in LTP.
    139 
    140   Many of the system calls in the CKI are tested by LTP. For a given
    141   system call an LTP test may or may not exist, that LTP test may or may
    142   not be currently compiling properly for Android, the test may not be
    143   stable, the test may not be running due to environment issues or
    144   passing. This class looks at various sources of information to determine
    145   the current test coverage of system calls in the CKI from LTP.
    146 
    147   Note that due to some deviations in LTP of tests from the common naming
    148   convention there there may be tests that are flagged here as not having
    149   coverage when in fact they do.
    150   """
    151 
    152   LTP_KERNEL_ROOT = os.path.join(os.environ["ANDROID_BUILD_TOP"],
    153                                  "external/ltp/testcases/kernel")
    154   LTP_KERNEL_TESTSUITES = ["syscalls", "timers"]
    155   DISABLED_IN_LTP_PATH = os.path.join(os.environ["ANDROID_BUILD_TOP"],
    156                         "external/ltp/android/tools/disabled_tests.txt")
    157 
    158   ltp_full_set = []
    159 
    160   cki_syscalls = []
    161 
    162   disabled_in_ltp = []
    163   disabled_in_vts_ltp = vts_disabled.DISABLED_TESTS
    164   stable_in_vts_ltp = vts_stable.STABLE_TESTS
    165 
    166   syscall_tests = {}
    167   disabled_tests = {}
    168 
    169   def __init__(self, arch):
    170     self._arch = arch
    171 
    172   def load_ltp_tests(self):
    173     """Load the list of LTP syscall tests.
    174 
    175     Load the list of all syscall tests existing in LTP.
    176     """
    177     for testsuite in self.LTP_KERNEL_TESTSUITES:
    178       self.__load_ltp_testsuite(testsuite)
    179 
    180   def __load_ltp_testsuite(self, testsuite):
    181     root = os.path.join(self.LTP_KERNEL_ROOT, testsuite)
    182     for path, dirs, files in os.walk(root):
    183       for filename in files:
    184         basename, ext = os.path.splitext(filename)
    185         if ext != ".c": continue
    186         self.ltp_full_set.append("%s.%s" % (testsuite, basename))
    187 
    188   def load_ltp_disabled_tests(self):
    189     """Load the list of LTP tests not being compiled.
    190 
    191     The LTP repository in Android contains a list of tests which are not
    192     compiled due to incompatibilities with Android.
    193     """
    194     with open(self.DISABLED_IN_LTP_PATH) as fp:
    195       for line in fp:
    196         line = line.strip()
    197         if not line: continue
    198         test_re = re.compile(r"^(\w+)")
    199         test_match = re.match(test_re, line)
    200         if not test_match: continue
    201         self.disabled_in_ltp.append(test_match.group(1))
    202 
    203   def ltp_test_special_cases(self, syscall, test):
    204     """Detect special cases in syscall to LTP mapping.
    205 
    206     Most syscall tests in LTP follow a predictable naming
    207     convention, but some do not. Detect known special cases.
    208 
    209     Args:
    210       syscall: The name of a syscall.
    211       test: The name of a testcase.
    212 
    213     Returns:
    214       A boolean indicating whether the given syscall is tested
    215       by the given testcase.
    216     """
    217     compat_syscalls = [ "chown32", "fchown32", "getegid32", "geteuid32",
    218             "getgid32", "getgroups32", "getresgid32", "getresuid32",
    219             "getuid32", "lchown32", "setfsgid32", "setfsuid32", "setgid32",
    220             "setgroups32", "setregid32", "setresgid32", "setresuid32",
    221             "setreuid32", "setuid32"]
    222     if syscall in compat_syscalls:
    223         test_re = re.compile(r"^%s\d+$" % syscall[0:-2])
    224         if re.match(test_re, test):
    225             return True
    226     if syscall == "_llseek" and test.startswith("llseek"):
    227       return True
    228     if syscall in ("arm_fadvise64_", "fadvise64_") and \
    229       test.startswith("posix_fadvise"):
    230       return True
    231     if syscall in ("arm_sync_file_range", "sync_file_range2") and \
    232       test.startswith("sync_file_range"):
    233       return True
    234     if syscall == "clock_nanosleep" and test == "clock_nanosleep2_01":
    235       return True
    236     if syscall in ("epoll_ctl", "epoll_create") and test == "epoll-ltp":
    237       return True
    238     if syscall == "futex" and test.startswith("futex_"):
    239       return True
    240     if syscall == "get_thread_area" and test == "set_thread_area01":
    241       return True
    242     if syscall == "inotify_add_watch" or syscall == "inotify_rm_watch":
    243       test_re = re.compile(r"^inotify\d+$")
    244       if re.match(test_re, test):
    245         return True
    246     inotify_init_tests = [ "inotify01", "inotify02", "inotify03", "inotify04" ]
    247     if syscall == "inotify_init" and test in inotify_init_tests:
    248         return True
    249     if syscall == "lsetxattr" and test.startswith("lgetxattr"):
    250         return True
    251     if syscall == "newfstatat":
    252       test_re = re.compile(r"^fstatat\d+$")
    253       if re.match(test_re, test):
    254         return True
    255     if syscall in ("prlimit", "ugetrlimit") and test == "getrlimit03":
    256       return True
    257     if syscall == "rt_sigtimedwait" and test == "sigwaitinfo01":
    258       return True
    259     shutdown_tests = [ "send01", "sendmsg01", "sendto01" ]
    260     if syscall == "shutdown" and test in shutdown_tests:
    261         return True
    262 
    263     return False
    264 
    265   def match_syscalls_to_tests(self, syscalls):
    266     """Match syscalls with tests in LTP.
    267 
    268     Create a mapping from CKI syscalls and tests in LTP. This mapping can
    269     largely be determined using a common naming convention in the LTP file
    270     hierarchy but there are special cases that have to be taken care of.
    271 
    272     Args:
    273       syscalls: List of syscall structures containing all syscalls
    274         in the CKI.
    275     """
    276     for syscall in syscalls:
    277       if self._arch is not None and self._arch not in syscall:
    278         continue
    279       self.cki_syscalls.append(syscall)
    280       self.syscall_tests[syscall["name"]] = []
    281       # LTP does not use the 64 at the end of syscall names for testcases.
    282       ltp_syscall_name = syscall["name"]
    283       if ltp_syscall_name.endswith("64"):
    284         ltp_syscall_name = ltp_syscall_name[0:-2]
    285       # Most LTP syscalls have source files for the tests that follow
    286       # a naming convention in the regexp below. Exceptions exist though.
    287       # For now those are checked for specifically.
    288       test_re = re.compile(r"^%s_?0?\d\d?$" % ltp_syscall_name)
    289       for full_test_name in self.ltp_full_set:
    290         testsuite, test = full_test_name.split('.')
    291         if (re.match(test_re, test) or
    292             self.ltp_test_special_cases(ltp_syscall_name, test)):
    293           # The filenames of the ioctl tests in LTP do not match the name
    294           # of the testcase defined in that source, which is what shows
    295           # up in VTS.
    296           if testsuite == "syscalls" and ltp_syscall_name == "ioctl":
    297             full_test_name = "syscalls.ioctl01_02"
    298           # Likewise LTP has a test named epoll01, which is built as an
    299           # executable named epoll-ltp, and tests the epoll_{create,ctl}
    300           # syscalls.
    301           if full_test_name == "syscalls.epoll-ltp":
    302             full_test_name = "syscalls.epoll01"
    303           self.syscall_tests[syscall["name"]].append(full_test_name)
    304       for e in EXTERNAL_TESTS:
    305         if e[0] == syscall["name"]:
    306           self.syscall_tests[syscall["name"]].append(e[1])
    307     self.cki_syscalls.sort(key=lambda tup: tup["name"])
    308 
    309   def update_test_status(self):
    310     """Populate test configuration and output for all CKI syscalls.
    311 
    312     Go through VTS test configuration to populate data for all CKI syscalls.
    313     """
    314     for syscall in self.cki_syscalls:
    315       self.disabled_tests[syscall["name"]] = []
    316       if not self.syscall_tests[syscall["name"]]:
    317         continue
    318       for full_test_name in self.syscall_tests[syscall["name"]]:
    319         if full_test_name in [t[1] for t in EXTERNAL_TESTS]:
    320           continue
    321         _, test = full_test_name.split('.')
    322         # The VTS LTP stable list is composed of tuples of the test name and
    323         # a boolean flag indicating whether it is mandatory.
    324         stable_vts_ltp_testnames = [i[0] for i in self.stable_in_vts_ltp]
    325         if (test in self.disabled_in_ltp or
    326             full_test_name in self.disabled_in_vts_ltp or
    327             ("%s_32bit" % full_test_name not in stable_vts_ltp_testnames and
    328              "%s_64bit" % full_test_name not in stable_vts_ltp_testnames)):
    329           self.disabled_tests[syscall["name"]].append(full_test_name)
    330           continue
    331 
    332   def syscall_arch_string(self, syscall, arch):
    333     """Return a string showing whether the arch supports the given syscall."""
    334     if arch not in syscall or not syscall[arch]:
    335       return " "
    336     else:
    337       return "*"
    338 
    339   def output_results(self):
    340     """Pretty print the CKI syscall LTP coverage."""
    341     count = 0
    342     uncovered = 0
    343 
    344     print ""
    345     print "         Covered Syscalls"
    346     for syscall in self.cki_syscalls:
    347       if (len(self.syscall_tests[syscall["name"]]) -
    348           len(self.disabled_tests[syscall["name"]]) <= 0):
    349         continue
    350       if not count % 20:
    351         print ("%25s   Disabled Enabled arm64 arm x86_64 x86 -----------" %
    352                "-------------")
    353       enabled = (len(self.syscall_tests[syscall["name"]]) -
    354                  len(self.disabled_tests[syscall["name"]]))
    355       if enabled > 9:
    356         column_sp = "      "
    357       else:
    358         column_sp = "       "
    359       sys.stdout.write("%25s   %s        %s%s%s     %s   %s      %s\n" %
    360                        (syscall["name"], len(self.disabled_tests[syscall["name"]]),
    361                         enabled, column_sp,
    362                         self.syscall_arch_string(syscall, "arm64"),
    363                         self.syscall_arch_string(syscall, "arm"),
    364                         self.syscall_arch_string(syscall, "x86_64"),
    365                         self.syscall_arch_string(syscall, "x86")))
    366       count += 1
    367 
    368     count = 0
    369     print "\n"
    370     print "       Uncovered Syscalls"
    371     for syscall in self.cki_syscalls:
    372       if (len(self.syscall_tests[syscall["name"]]) -
    373           len(self.disabled_tests[syscall["name"]]) > 0):
    374         continue
    375       if not count % 20:
    376         print ("%25s   Disabled Enabled arm64 arm x86_64 x86 -----------" %
    377                "-------------")
    378       enabled = (len(self.syscall_tests[syscall["name"]]) -
    379                  len(self.disabled_tests[syscall["name"]]))
    380       if enabled > 9:
    381         column_sp = "      "
    382       else:
    383         column_sp = "       "
    384       sys.stdout.write("%25s   %s        %s%s%s     %s   %s      %s\n" %
    385                        (syscall["name"], len(self.disabled_tests[syscall["name"]]),
    386                         enabled, column_sp,
    387                         self.syscall_arch_string(syscall, "arm64"),
    388                         self.syscall_arch_string(syscall, "arm"),
    389                         self.syscall_arch_string(syscall, "x86_64"),
    390                         self.syscall_arch_string(syscall, "x86")))
    391       uncovered += 1
    392       count += 1
    393 
    394     print ""
    395     print ("Total uncovered syscalls: %s out of %s" %
    396            (uncovered, len(self.cki_syscalls)))
    397 
    398   def output_summary(self):
    399     """Print a one line summary of the CKI syscall LTP coverage.
    400 
    401     Pretty prints a one line summary of the CKI syscall coverage in LTP
    402     for the specified architecture.
    403     """
    404     uncovered_with_test = 0
    405     uncovered_without_test = 0
    406     for syscall in self.cki_syscalls:
    407       if (len(self.syscall_tests[syscall["name"]]) -
    408           len(self.disabled_tests[syscall["name"]]) > 0):
    409         continue
    410       if (len(self.disabled_tests[syscall["name"]]) > 0):
    411         uncovered_with_test += 1
    412       else:
    413         uncovered_without_test += 1
    414     print ("arch, cki syscalls, uncovered with disabled test(s), "
    415            "uncovered with no tests, total uncovered")
    416     print ("%s, %s, %s, %s, %s" % (self._arch, len(self.cki_syscalls),
    417                                 uncovered_with_test, uncovered_without_test,
    418                                 uncovered_with_test + uncovered_without_test))
    419 
    420   def add_syscall(self, cki, syscall, arch):
    421     """Note that a syscall has been seen for a particular arch."""
    422     seen = False
    423     for s in cki.syscalls:
    424       if s["name"] == syscall:
    425         s[arch]= True
    426         seen = True
    427         break
    428     if not seen:
    429       cki.syscalls.append({"name":syscall, arch:True})
    430 
    431   def delete_syscall(self, cki, syscall):
    432     cki.syscalls = list(filter(lambda i: i["name"] != syscall, cki.syscalls))
    433 
    434   def check_blacklist(self, cki, error_on_match):
    435     unlisted_syscalls = []
    436     for s in cki.syscalls:
    437       if s["name"] in CKI_BLACKLIST:
    438         if error_on_match:
    439           print "Syscall %s found in both bionic CKI and blacklist!" % s["name"]
    440           sys.exit()
    441       else:
    442         unlisted_syscalls.append(s)
    443     cki.syscalls = unlisted_syscalls
    444 
    445   def get_x86_64_kernel_syscalls(self, cki):
    446     """Retrieve the list of syscalls for x86_64."""
    447     proc = subprocess.Popen(['curl', x86_64_syscall_tbl_url], stdout=subprocess.PIPE)
    448     while True:
    449       line = proc.stdout.readline()
    450       if line != b'':
    451         test_re = re.compile(r"^\d+\s+\w+\s+(\w+)\s+(__x64_sys|__x32_compat_sys)")
    452         test_match = re.match(test_re, line)
    453         if test_match:
    454           syscall = test_match.group(1)
    455           self.add_syscall(cki, syscall, "x86_64")
    456       else:
    457         break
    458 
    459   def get_x86_kernel_syscalls(self, cki):
    460     """Retrieve the list of syscalls for x86."""
    461     proc = subprocess.Popen(['curl', x86_syscall_tbl_url], stdout=subprocess.PIPE)
    462     while True:
    463       line = proc.stdout.readline()
    464       if line != b'':
    465         test_re = re.compile(r"^\d+\s+i386\s+(\w+)\s+sys_")
    466         test_match = re.match(test_re, line)
    467         if test_match:
    468           syscall = test_match.group(1)
    469           self.add_syscall(cki, syscall, "x86")
    470       else:
    471         break
    472 
    473   def get_arm_kernel_syscalls(self, cki):
    474     """Retrieve the list of syscalls for arm."""
    475     proc = subprocess.Popen(['curl', arm_syscall_tbl_url], stdout=subprocess.PIPE)
    476     while True:
    477       line = proc.stdout.readline()
    478       if line != b'':
    479         test_re = re.compile(r"^\d+\s+\w+\s+(\w+)\s+sys_")
    480         test_match = re.match(test_re, line)
    481         if test_match:
    482           syscall = test_match.group(1)
    483           self.add_syscall(cki, syscall, "arm")
    484       else:
    485         break
    486 
    487   def get_arm64_kernel_syscalls(self, cki):
    488     """Retrieve the list of syscalls for arm64."""
    489     # Add AArch64 syscalls
    490     proc = subprocess.Popen(['curl', unistd_h_url], stdout=subprocess.PIPE)
    491     while True:
    492       line = proc.stdout.readline()
    493       if line != b'':
    494         test_re = re.compile(r"^#define __NR(3264)?_(\w+)\s+(\d+)$")
    495         test_match = re.match(test_re, line)
    496         if test_match:
    497           syscall = test_match.group(2)
    498           if (syscall == "sync_file_range2" or
    499               syscall == "arch_specific_syscall" or
    500               syscall == "syscalls"):
    501               continue
    502           self.add_syscall(cki, syscall, "arm64")
    503       else:
    504         break
    505     # Add AArch32 syscalls
    506     proc = subprocess.Popen(['curl', arm64_unistd32_h_url], stdout=subprocess.PIPE)
    507     while True:
    508       line = proc.stdout.readline()
    509       if line != b'':
    510         test_re = re.compile(r"^#define __NR(3264)?_(\w+)\s+(\d+)$")
    511         test_match = re.match(test_re, line)
    512         if test_match:
    513           syscall = test_match.group(2)
    514           self.add_syscall(cki, syscall, "arm64")
    515       else:
    516         break
    517 
    518   def get_kernel_syscalls(self, cki, arch):
    519     self.get_arm64_kernel_syscalls(cki)
    520     self.get_arm_kernel_syscalls(cki)
    521     self.get_x86_kernel_syscalls(cki)
    522     self.get_x86_64_kernel_syscalls(cki)
    523 
    524     # restart_syscall is a special syscall which the kernel issues internally
    525     # when a process is resumed with SIGCONT.  seccomp whitelists this syscall,
    526     # but it is not part of the CKI or meaningfully testable from userspace.
    527     # See restart_syscall(2) for more details.
    528     self.delete_syscall(cki, "restart_syscall")
    529 
    530 if __name__ == "__main__":
    531   parser = argparse.ArgumentParser(description="Output list of system calls "
    532           "in the Common Kernel Interface and their VTS LTP coverage.")
    533   parser.add_argument("-a", "--arch", help="only show syscall CKI for specific arch")
    534   parser.add_argument("-l", action="store_true",
    535                       help="list CKI syscalls only, without coverage")
    536   parser.add_argument("-s", action="store_true",
    537                       help="print one line summary of CKI coverage for arch")
    538   parser.add_argument("-f", action="store_true",
    539                       help="only check syscalls with known Android use")
    540   parser.add_argument("-k", action="store_true",
    541                       help="use lowest supported kernel version instead of tip")
    542 
    543   args = parser.parse_args()
    544   if args.arch is not None and args.arch not in gensyscalls.all_arches:
    545     print "Arch must be one of the following:"
    546     print gensyscalls.all_arches
    547     exit(-1)
    548 
    549   if args.k:
    550     minversion = "4.9"
    551     print "Checking kernel version %s" % minversion
    552     minversion = "?h=v" + minversion
    553     unistd_h_url += stable_url + unistd_h + minversion
    554     arm64_unistd32_h_url += stable_url + arm64_unistd32_h + minversion
    555     arm_syscall_tbl_url += stable_url + arm_syscall_tbl + minversion
    556     x86_syscall_tbl_url += stable_url + x86_syscall_tbl + minversion
    557     x86_64_syscall_tbl_url += stable_url + x86_64_syscall_tbl + minversion
    558   else:
    559     unistd_h_url += tip_url + unistd_h
    560     arm64_unistd32_h_url += tip_url + arm64_unistd32_h
    561     arm_syscall_tbl_url += tip_url + arm_syscall_tbl
    562     x86_syscall_tbl_url += tip_url + x86_syscall_tbl
    563     x86_64_syscall_tbl_url += tip_url + x86_64_syscall_tbl
    564 
    565   cki = gensyscalls.SysCallsTxtParser()
    566   cki_cov = CKI_Coverage(args.arch)
    567 
    568   if args.f:
    569     cki.parse_file(os.path.join(bionic_libc_root, "SYSCALLS.TXT"))
    570     cki.parse_file(os.path.join(bionic_libc_root, "SECCOMP_WHITELIST_APP.TXT"))
    571     cki.parse_file(os.path.join(bionic_libc_root, "SECCOMP_WHITELIST_COMMON.TXT"))
    572     cki.parse_file(os.path.join(bionic_libc_root, "SECCOMP_WHITELIST_SYSTEM.TXT"))
    573     cki.parse_file(os.path.join(bionic_libc_root, "SECCOMP_WHITELIST_GLOBAL.TXT"))
    574     cki_cov.check_blacklist(cki, True)
    575   else:
    576     cki_cov.get_kernel_syscalls(cki, args.arch)
    577     cki_cov.check_blacklist(cki, False)
    578 
    579   if args.l:
    580     for syscall in cki.syscalls:
    581       if args.arch is None or syscall[args.arch]:
    582         print syscall["name"]
    583     exit(0)
    584 
    585   cki_cov.load_ltp_tests()
    586   cki_cov.load_ltp_disabled_tests()
    587   cki_cov.match_syscalls_to_tests(cki.syscalls)
    588   cki_cov.update_test_status()
    589 
    590   beta_string = ("*** WARNING: This script is still in development and may\n"
    591                  "*** report both false positives and negatives.")
    592   print beta_string
    593 
    594   if args.s:
    595     cki_cov.output_summary()
    596     exit(0)
    597 
    598   cki_cov.output_results()
    599   print beta_string
    600