summaryrefslogblamecommitdiffstats
path: root/devtools/create-linux-syscall
blob: 0b8e800a0dce0a3872ca005deca7a9f883d406f3 (plain) (tree)











































































































































































































































































































































                                                                                                                   
#!/usr/bin/env python3

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)