1  #!/usr/bin/python3
       2  # Consistency checks for glibc system call lists.
       3  # Copyright (C) 2020-2023 Free Software Foundation, Inc.
       4  # This file is part of the GNU C Library.
       5  #
       6  # The GNU C Library is free software; you can redistribute it and/or
       7  # modify it under the terms of the GNU Lesser General Public
       8  # License as published by the Free Software Foundation; either
       9  # version 2.1 of the License, or (at your option) any later version.
      10  #
      11  # The GNU C Library is distributed in the hope that it will be useful,
      12  # but WITHOUT ANY WARRANTY; without even the implied warranty of
      13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14  # Lesser General Public License for more details.
      15  #
      16  # You should have received a copy of the GNU Lesser General Public
      17  # License along with the GNU C Library; if not, see
      18  # <http://www.gnu.org/licenses/>.
      19  
      20  import argparse
      21  import sys
      22  
      23  import glibcextract
      24  import glibcsyscalls
      25  
      26  def main():
      27      """The main entry point."""
      28      parser = argparse.ArgumentParser(
      29          description="System call list consistency checks")
      30      parser.add_argument('--cc', metavar='CC', required=True,
      31                          help='C compiler (including options) to use')
      32      parser.add_argument('syscall_numbers_list', metavar='PATH',
      33                          help='Path to the list of system call numbers')
      34      parser.add_argument('syscall_names_list', metavar='PATH',
      35                          help='Path to the list of system call names')
      36  
      37      args = parser.parse_args()
      38  
      39      glibc_constants = glibcsyscalls.load_arch_syscall_header(
      40          args.syscall_numbers_list)
      41      with open(args.syscall_names_list) as inp:
      42          glibc_names = glibcsyscalls.SyscallNamesList(inp)
      43      kernel_constants = glibcsyscalls.kernel_constants(args.cc)
      44      kernel_version = glibcsyscalls.linux_kernel_version(args.cc)
      45  
      46      errors = 0
      47      warnings = False
      48      for name in glibc_constants.keys() & kernel_constants.keys():
      49          if glibc_constants[name] != kernel_constants[name]:
      50              print("error: syscall {!r} number mismatch: glibc={!r} kernel={!r}"
      51                    .format(name, glibc_constants[name], kernel_constants[name]))
      52              errors = 1
      53  
      54      # The architecture-specific list in the glibc tree must be a
      55      # subset of the global list of system call names.
      56      for name in glibc_constants.keys() - set(glibc_names.syscalls):
      57          print("error: architecture syscall {!r} missing from global names list"
      58                .format(name))
      59          errors = 1
      60  
      61      for name in glibc_constants.keys() - kernel_constants.keys():
      62          print("info: glibc syscall {!r} not known to kernel".format(name))
      63          warnings = True
      64  
      65      # If the glibc-recorded kernel version is not older than the
      66      # installed kernel headers, the glibc system call set must be a
      67      # superset of the kernel system call set.
      68      if glibc_names.kernel_version >= kernel_version:
      69          for name in kernel_constants.keys() - glibc_constants.keys():
      70              print("error: kernel syscall {!r} ({}) not known to glibc"
      71                    .format(name, kernel_constants[name]))
      72              errors = 1
      73      else:
      74          for name in kernel_constants.keys() - glibc_constants.keys():
      75              print("warning: kernel syscall {!r} ({}) not known to glibc"
      76                    .format(name, kernel_constants[name]))
      77              warnings = True
      78  
      79      if errors > 0 or warnings:
      80          print("info: glibc tables are based on kernel version {}".format(
      81              ".".join(map(str, glibc_names.kernel_version))))
      82          print("info: installed kernel headers are version {}".format(
      83              ".".join(map(str, kernel_version))))
      84  
      85      sys.exit(errors)
      86  
      87  if __name__ == '__main__':
      88      main()