summaryrefslogtreecommitdiffstats
path: root/devtools/create-linux-syscall
blob: 2a51543a5696997704e36c72819d5604ba82e9e4 (plain) (blame)
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
#!/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)