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
20This module generates a report on the syscalls in the Android CKI and
21their coverage in VTS LTP.
22
23The coverage report provides, for each syscall in the CKI, the number of
24enabled and disabled LTP tests for the syscall in VTS. If VTS test output is
25supplied, the report instead provides the number of disabled, skipped, failing,
26and passing tests for each syscall.
27
28Assumptions are made about the structure of files in LTP source
29and the naming convention.
30"""
31
32import argparse
33import os.path
34import re
35import sys
36import xml.etree.ElementTree as ET
37import subprocess
38
39if "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
44sys.path.append(os.path.join(os.environ["ANDROID_BUILD_TOP"],
45                "bionic/libc/tools"))
46import gensyscalls
47
48sys.path.append(os.path.join(os.environ["ANDROID_BUILD_TOP"],
49                             "test/vts-testcase/kernel/ltp/configs"))
50import disabled_tests as vts_disabled
51import stable_tests as vts_stable
52
53bionic_libc_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc")
54
55src_url_start = 'https://git.kernel.org/pub/scm/linux/kernel/git/'
56tip_url = 'torvalds/linux.git/plain/'
57stable_url = 'stable/linux.git/plain/'
58unistd_h = 'include/uapi/asm-generic/unistd.h'
59arm64_unistd32_h = 'arch/arm64/include/asm/unistd32.h'
60arm_syscall_tbl = 'arch/arm/tools/syscall.tbl'
61x86_syscall_tbl = 'arch/x86/entry/syscalls/syscall_32.tbl'
62x86_64_syscall_tbl = 'arch/x86/entry/syscalls/syscall_64.tbl'
63
64unistd_h_url = src_url_start
65arm64_unistd32_h_url = src_url_start
66arm_syscall_tbl_url = src_url_start
67x86_syscall_tbl_url = src_url_start
68x86_64_syscall_tbl_url = src_url_start
69
70# Syscalls which are either banned, optional, or deprecated, so not part of the
71# CKI.
72CKI_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
129EXTERNAL_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
137class 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
530if __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