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