#!/usr/bin/env python3 # See LICENSE file for copyright and license details. import sys lines = [] try: while True: lines.append(input()) except EOFError: pass def remove_comments(text): return ' '.join(t.split('/*')[0] for t in text.split('*/')) functions = frozenset(sys.argv[1:]) if len(sys.argv) > 1 else None lines = remove_comments(' '.join(lines)).replace('\t', ' ') lines = [line.strip() for line in lines.split(';') if line] lines = [' '.join(word for word in line.split(' ')[1:] if word) for line in lines if line.replace('//', '').strip().startswith('asmlinkage ')] lines = sorted(lines) def map_type(typ): orig_typ = typ if typ.startswith('signed ') and typ != 'signed char': typ = typ[len('signed '):] typemap = { 'void' : 'LIBSYSCALLS_TYPE_VOID', 'char' : 'LIBSYSCALLS_TYPE_CHAR', 'signed char' : 'LIBSYSCALLS_TYPE_SCHAR', 'unsigned char' : 'LIBSYSCALLS_TYPE_UCHAR', 'short int' : 'LIBSYSCALLS_TYPE_SHORT', 'unsigned short int' : 'LIBSYSCALLS_TYPE_USHORT', 'int' : 'LIBSYSCALLS_TYPE_INT', 'unsigned int' : 'LIBSYSCALLS_TYPE_UINT', 'long int' : 'LIBSYSCALLS_TYPE_LONG', 'unsigned long int' : 'LIBSYSCALLS_TYPE_ULONG', 'long long int' : 'LIBSYSCALLS_TYPE_LLONG', 'unsigned long long int' : 'LIBSYSCALLS_TYPE_ULLONG', 'size_t' : 'LIBSYSCALLS_TYPE_SIZE', 'ssize_t' : 'LIBSYSCALLS_TYPE_SSIZE', 'ptrdiff_t' : 'LIBSYSCALLS_TYPE_PTRDIFF', 'float' : 'LIBSYSCALLS_TYPE_FLOAT', 'double' : 'LIBSYSCALLS_TYPE_DOUBLE', 'long double' : 'LIBSYSCALLS_TYPE_LDOUBLE', 'int8_t' : 'LIBSYSCALLS_TYPE_INT8', 'uint8_t' : 'LIBSYSCALLS_TYPE_UINT8', 'int16_t' : 'LIBSYSCALLS_TYPE_INT16', 'uint16_t' : 'LIBSYSCALLS_TYPE_UINT16', 'int32_t' : 'LIBSYSCALLS_TYPE_INT32', 'uint32_t' : 'LIBSYSCALLS_TYPE_UINT32', 'int64_t' : 'LIBSYSCALLS_TYPE_INT64', 'uint64_t' : 'LIBSYSCALLS_TYPE_UINT64', 'struct sockaddr' : 'LIBSYSCALLS_TYPE_STRUCT_SOCKADDR', 'struct timex' : 'LIBSYSCALLS_TYPE_STRUCT_TIMEX', 'struct old_timex32' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_TIMEX32', 'struct iovec' : 'LIBSYSCALLS_TYPE_STRUCT_IOVEC_ARRAY', 'struct statfs' : 'LIBSYSCALLS_TYPE_STRUCT_STATFS', 'struct statfs64' : 'LIBSYSCALLS_TYPE_STRUCT_STATFS64', 'struct stat' : 'LIBSYSCALLS_TYPE_STRUCT_STAT', 'struct stat64' : 'LIBSYSCALLS_TYPE_STRUCT_STAT64', 'struct old_stat' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_STAT', 'struct mount_attr' : 'LIBSYSCALLS_TYPE_STRUCT_MOUNT_ATTR', 'struct ustat' : 'LIBSYSCALLS_TYPE_STRUCT_USTAT', 'struct statx' : 'LIBSYSCALLS_TYPE_STRUCT_STATX', 'struct linux_dirent' : 'LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT', 'struct linux_dirent64' : 'LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT64', 'struct old_linux_dirent' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_LINUX_DIRENT', 'struct open_how' : 'LIBSYSCALLS_TYPE_STRUCT_OPEN_HOW', 'struct iob' : 'LIBSYSCALLS_TYPE_STRUCT_IOB', 'struct io_event' : 'LIBSYSCALLS_TYPE_STRUCT_IO_EVENT', 'struct timespec' : 'LIBSYSCALLS_TYPE_STRUCT_TIMESPEC', 'struct old_timespec32' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_TIMESPEC32', 'struct aio_sigset' : 'LIBSYSCALLS_TYPE_STRUCT_AIO_SIGSET', 'struct io_uring_params' : 'LIBSYSCALLS_TYPE_STRUCT_IO_URING_PARAMS', 'struct epoll_event' : 'LIBSYSCALLS_TYPE_STRUCT_EPOLL_EVENT', 'struct pollfd' : 'LIBSYSCALLS_TYPE_STRUCT_POLLFD', 'struct utimbuf' : 'LIBSYSCALLS_TYPE_STRUCT_UTIMBUF', 'struct old_utimbuf32' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_UTIMBUF32', 'struct old_timeval' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_TIMEVAL', 'struct old_timeval32' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_TIMEVAL32', 'struct sel_arg_struct' : 'LIBSYSCALLS_TYPE_STRUCT_SEL_ARG_STRUCT', 'struct tms' : 'LIBSYSCALLS_TYPE_STRUCT_TMS', 'struct itimerspec' : 'LIBSYSCALLS_TYPE_STRUCT_ITIMERSPEC', 'struct old_itimerspec32' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_ITIMERSPEC32', 'struct siginfo' : 'LIBSYSCALLS_TYPE_STRUCT_SIGINFO', 'struct rusage' : 'LIBSYSCALLS_TYPE_STRUCT_RUSAGE', 'struct robust_list_head' : 'LIBSYSCALLS_TYPE_STRUCT_ROBUST_LIST_HEAD', 'struct futex_waitv' : 'LIBSYSCALLS_TYPE_STRUCT_FUTEX_WAITV', 'struct old_itimerval' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_ITIMERVAL', 'struct kexec_segment' : 'LIBSYSCALLS_TYPE_STRUCT_KEXEC_SEGMENT', 'struct sigevent' : 'LIBSYSCALLS_TYPE_STRUCT_SIGEVENT', 'struct sched_param' : 'LIBSYSCALLS_TYPE_STRUCT_SCHED_PARAM', 'struct sigaltstack' : 'LIBSYSCALLS_TYPE_STRUCT_SIGALTSTACK', 'struct sigaction' : 'LIBSYSCALLS_TYPE_STRUCT_SIGACTION', 'struct old_sigaction' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_SIGACTION', 'struct new_utsname' : 'LIBSYSCALLS_TYPE_STRUCT_NEW_UTSNAME', 'struct old_utsname' : 'LIBSYSCALLS_TYPE_STRUCT_OLD_UTSNAME', 'struct oldold_utsname' : 'LIBSYSCALLS_TYPE_STRUCT_OLDOLD_UTSNAME', 'struct rlimit' : 'LIBSYSCALLS_TYPE_STRUCT_RLIMIT', 'struct rlimit64' : 'LIBSYSCALLS_TYPE_STRUCT_RLIMIT64', 'struct file_handle' : 'LIBSYSCALLS_TYPE_STRUCT_FILE_HANDLE', 'struct timezone' : 'LIBSYSCALLS_TYPE_STRUCT_TIMEZONE', 'struct sysinfo' : 'LIBSYSCALLS_TYPE_STRUCT_SYSINFO', 'struct mq_attr' : 'LIBSYSCALLS_TYPE_STRUCT_MQ_ATTR', 'struct msqid_ds' : 'LIBSYSCALLS_TYPE_STRUCT_MSQID_DS', 'struct msgbuf' : 'LIBSYSCALLS_TYPE_STRUCT_MSGBUF', 'struct semid_ds' : 'LIBSYSCALLS_TYPE_STRUCT_SEMID_DS', 'struct sembuf' : 'LIBSYSCALLS_TYPE_STRUCT_SEMBUF', 'struct shmid_ds' : 'LIBSYSCALLS_TYPE_STRUCT_SHMID_DS', 'struct user_msghdr' : 'LIBSYSCALLS_TYPE_STRUCT_MSGHDR', 'struct mmsghdr' : 'LIBSYSCALLS_TYPE_STRUCT_MMSGHDR', 'struct clone_args' : 'LIBSYSCALLS_TYPE_STRUCT_CLONE_ARGS', 'struct perf_event_attr' : 'LIBSYSCALLS_TYPE_STRUCT_PERF_EVENT_ATTR', 'struct sched_attr' : 'LIBSYSCALLS_TYPE_STRUCT_SCHED_ATTR', 'struct rseq' : 'LIBSYSCALLS_TYPE_STRUCT_RSEQ', 'struct landlock_ruleset_attr' : 'LIBSYSCALLS_TYPE_STRUCT_LANDLOCK_RULESET_ATTR', 'struct cachestat_range' : 'LIBSYSCALLS_TYPE_STRUCT_CACHESTAT_RANGE', 'struct cachestat' : 'LIBSYSCALLS_TYPE_STRUCT_CACHESTAT', 'struct mmap_arg_struct' : 'LIBSYSCALLS_TYPE_STRUCT_MMAP_ARG_STRUCT', 'union bpf_attr' : 'LIBSYSCALLS_TYPE_UNION_BPF_ATTR', 'u8' : 'uint8_t', 'u16' : 'uint16_t', 'u32' : 'uint32_t', 'u64' : 'uint64_t', 's8' : 'int8_t', 's16' : 'int16_t', 's32' : 'int32_t', 's64' : 'int64_t', 'gid_t' : 'gid32_t', 'compat_gid_t' : 'gid32_t', 'gid32_t' : 'u32', 'old_gid_t' : 'unsigned short int', 'uid_t' : 'uid32_t', 'compat_uid_t' : 'uid32_t', 'uid32_t' : 'u32', 'old_uid_t' : 'unsigned short int', 'gid16_t' : 'u16', 'uid16_t' : 'u16', 'pid_t' : 'int', 'umode_t' : 'unsigned short int', 'aio_context_t' : 'unsigned long int', 'sigset_t' : 'unsigned long int', 'loff_t' : 'long long int', 'off_t' : 'long int', 'qid_t' : 'uid32_t', 'clockid_t' : 'int', 'timer_t' : 'int', 'mqd_t' : 'int', 'key_t' : 'int', 'rwf_t' : 'int', 'time_t' : 'long int', 'old_time_t' : 'long int', 'old_time32_t' : 's32', 'time64_t' : 's64', # also defined as `long long int` 'key_serial_t' : 'int32_t', 'old_sigset_t' : 'unsigned long int', 'intptr_t' : 'long int', 'uintptr_t' : 'unsigned long int', 'compat_ulong_t' : 'u32', 'fd_set' : 'LIBSYSCALLS_TYPE_FD_SET' } while not typ.startswith('LIBSYSCALLS'): if typ == '???': typ = typemap.get(typ, 'LIBSYSCALLS_TYPE_UNKNOWN /* TO'+'DO */') else: typ = typemap.get(typ, 'LIBSYSCALLS_TYPE_UNKNOWN /* TO'+'DO (%s) */' % typ) if typ.startswith('LIBSYSCALLS_TYPE_UNKNOWN') and (orig_typ.split(' ')[0] in ('struct', 'union')): typ = 'LIBSYSCALLS_TYPE_STRUCT /* TO'+'DO */' return typ def get_type(param): old_param = [p for p in param.replace('*', ' * ').split(' ') if p and p != '__user'] param = [] width = '' sign = '' constness = '' require = None have_type = False for p in old_param: if p == 'volatile': pass elif p == 'restrict': pass elif p == 'long': width += 'long ' require = 'int' elif p == 'short': width += 'short ' require = 'int' elif p == 'signed': sign += 'signed ' require = 'int' elif p == 'unsigned': sign += 'unsigned ' require = 'int' elif p == 'struct': sign += 'struct ' elif p == 'union': sign += 'union ' elif p == 'enum': sign += 'enum ' elif p == 'const': constness = 'const' else: if require and p != require: param.append(sign + width + require) have_type = True if p == '*': param.append(constness + p) constness = '' elif not have_type: p = sign + width + p if p.startswith('struct __kernel_'): p = 'struct ' + p[len('struct __kernel_'):] elif p.startswith('struct __old_kernel_'): p = 'struct old_' + p[len('struct __old_kernel_'):] elif p.startswith('__kernel_'): p = p[len('__kernel_'):] elif p.startswith('__old_kernel_'): p = 'old_' + p[len('__old_kernel_'):] elif p.startswith('__'): p = p[len('__'):] param.append(p) have_type = True sign = '' width = '' require = None if require: param.append(sign + width.strip() + require) if len(param) == 1: return (map_type(param[0]), False, False) if param == ['char', 'const*']: return ('LIBSYSCALLS_TYPE_STRING', False, False) if param == ['void', '*']: return ('LIBSYSCALLS_TYPE_MEMORY_ADDRESS', False, False) if len(param) == 2 and param[1] == '*': return (map_type(param[0]), False, True) if len(param) == 2 and param[1] == 'const*': return (map_type(param[0]), True, False) return ('LIBSYSCALLS_TYPE_UNKNOWN /* TO'+'DO */', False, False) def format_mask(args): if len(args) == 0: return '0' if len(args) == 1: return '_' + str(args[0] + 1) return '(%s)' % ' | ' .join('_' + str(arg + 1) for arg in sorted(args)) queued = {} for line in lines: line = line.split(')')[0] [name, params] = line.split('(') name = name.split(' ') return_type, name = ' '.join(name[:-1]), name[-1] while name[0] == '*': return_type += '*' name = name[1:] if functions is not None and name not in functions: continue if return_type == 'long': return_type = '???' params = [param.strip() for param in params.split(',')] if params == ['void']: params = [] param_types = [] in_pointer_mask = [] out_pointer_mask = [] for i, param in enumerate(params): (typ, is_in, is_out) = get_type(param) param_types.append(typ) if is_in: in_pointer_mask.append(i) if is_out: out_pointer_mask.append(i) code = [] (return_type, return_type_ptr_in, return_type_ptr_out) = get_type(return_type) if return_type_ptr_in or return_type_ptr_out: return_type += ' *' return_type = return_type.replace('* *', '**') if False: code.append('\nstatic struct libsyscalls_syscall_abi libsyscalls_linux_syscall_%s = {' % name) code.append('\t.category = LIBSYSCALLS_CAT_SUPPORT_PENDING /* TO'+'DO */,') code.append('\t/* TO'+'DO .subcategory = , */') code.append('\t.min_argument_count = %i,%s' % (len(params), (' /* TO'+'DO */' if len(params) > 1 else ''))) code.append('\t.max_argument_count = %i,' % len(params)) code.append('\t.in_pointer_mask = %s,' % format_mask(in_pointer_mask)) code.append('\t.out_pointer_mask = %s,' % format_mask(out_pointer_mask)) code.append('\t.symbolic_mask = 0, /* TO'+'DO */') code.append('\t.symbolic_return = 0,') code.append('\t.expect_zero = 1, /* TO'+'DO */') code.append('\t.symbol_printer = ~0, /* TO'+'DO */') code.append('\t.return_type = %s%s' % (return_type, (',' if len(params) else ''))) if len(params): code.append('\t.parameters_types = {') for i, param_type in enumerate(param_types): code.append('\t\t' + param_type + ('' if i + 1 == len(param_types) else ',')) code.append('\t}') code.append('};') else: paramstr = '' for i, param_type in enumerate(param_types): if i: paramstr += ', ' paramstr += {(False, False) : '_', (True, False) : 'IN', (False, True) : 'OUT', (True, True) : 'BI'}[(i in in_pointer_mask), (i in out_pointer_mask)] paramstr += ',' + param_type.replace('LIBSYSCALLS_TYPE_', '') code.append('\nSYS(%s, /*CATEGORY*/, /*SUBCATEGORY*/, %i, ZERO(%s),' % (name, len(params), return_type.replace('LIBSYSCALLS_TYPE_', ''))) code.append('\tPARAMS(%s),' % paramstr) code.append('\t.symbolic_return = 0,') code.append('\t.symbol_printer = ~0') code.append(');') code = '\n'.join(code) if functions is None: print(code) else: queued[name] = code not_found = [] for name in sys.argv[1:]: if name in queued: print(queued[name]) else: not_found.append(name) if not_found: for name in not_found: print('Could not find ' + name, file = sys.stderr) sys.exit(1)