xref: /xnu-11215/tools/syscall_map.lua (revision 94d3b452)
1#!/usr/bin/env recon
2
3local cjson = require 'cjson'
4local lpeg = require 'lpeg'
5lpeg.locale(lpeg)
6
7-- Only certain regions of the master file should be parsed.
8-- The convention is that any `#if/#else/#endif` clauses are parsed, assuming the condition is true/defined, except for `COMPAT_GETFSSTAT`.
9
10local region_state = { valid = true, }
11local function in_valid_region(line)
12  -- Only C preprocessor directives can affect the region's validity.
13  if line:sub(1, 1) ~= '#' then
14    return region_state.valid
15  end
16
17  -- This is the only macro definition that is assumed to be undefined.
18  local assume_defined = not line:match('COMPAT_GETFSSTAT')
19  if line:match('^#if') then
20    region_state.valid = assume_defined
21  elseif line:match('^#else') then
22    region_state.valid = not region_state.valid
23  elseif line:match('^#endif') then
24    region_state.valid = true
25  end
26end
27
28-- Parse a syscall declaration line from `bsd/kern/syscalls.master` into a table with `name`, `number`, `arguments`, and `old` keys.
29
30-- Primitive tokens.
31local space = lpeg.S(' \t')^0
32local identifier = (lpeg.alnum + lpeg.P('_'))^1
33local numeric = lpeg.digit^1 / tonumber
34
35-- Matching the function name of the syscall declaration.
36local function_ptn = lpeg.Cg(identifier^1, 'name') * lpeg.P('(')
37local nosys_ptn = lpeg.P('e')^-1 * lpeg.P('nosys(')
38
39-- Matching an argument list.
40local arg = lpeg.C((1 - lpeg.S(',)'))^1)
41local args_ptn = lpeg.Ct(arg * (lpeg.P(',') * space * arg)^0)
42
43-- Matching a normal C-style declaration of the syscall.
44local decl_ptn = (1 - function_ptn)^1 * (function_ptn - nosys_ptn) *
45    lpeg.Cg(args_ptn, 'arguments')
46
47-- Matching an old breadcrumb, with empty arguments table.
48local old_ptn = lpeg.P('old') * space * lpeg.Cg(identifier^1, 'name') *
49    lpeg.Cg(lpeg.Cc(true), 'old') * lpeg.Cg(lpeg.Cc({}), 'arguments')
50local old_decl_ptn = (1 - old_ptn)^1 * old_ptn
51
52local syscall_ptn = lpeg.Ct(lpeg.Cg(numeric, 'number') *
53    (decl_ptn + old_decl_ptn))
54
55local bsd_syscalls = {}
56for line in io.stdin:lines() do
57  if in_valid_region(line) then
58    bsd_syscalls[#bsd_syscalls + 1] = syscall_ptn:match(line)
59  end
60end
61
62local syscalls = {
63  bsd_syscalls = bsd_syscalls,
64  mach_syscalls = {
65    -- Duplicate the names from `mach_trap_table` here.
66    { number = 10, name = 'mach_vm_allocate',
67      arguments = {
68        'mach_port_name_t target',
69        'mach_vm_address_t *address',
70        'mach_vm_size_t size',
71        'int flags',
72      },
73    },
74    { number = 11, name = 'mach_vm_purgable_control',
75      arguments = {
76        'mach_port_name_t target',
77        'mach_vm_offset_t address',
78        'vm_purgable_t control',
79        'int *state',
80      },
81    },
82    { number = 12, name = 'mach_vm_deallocate',
83      arguments = {
84        'mach_port_name_t target',
85        'mach_vm_address_t address',
86        'mach_vm_size_t size',
87      },
88    },
89    { number = 13, name = 'task_dyld_process_info_notify_get',
90      arguments = {
91        'mach_port_name_array_t names_addr',
92        'natural_t *names_count_addr',
93      },
94    },
95    { number = 14, name = 'mach_vm_protect',
96      arguments = {
97        'mach_port_name_t task',
98        'mach_vm_address_t address',
99        'mach_vm_size_t size',
100        'boolean_t set_maximum',
101        'vm_prot_t new_protection',
102      }
103    },
104    { number = 15, name = 'mach_vm_map',
105      arguments = {
106        'mach_port_name_t target',
107        'mach_vm_address_t *address',
108        'mach_vm_size_t size',
109        'mach_vm_offset_t mask',
110        'int flags',
111        'mem_entry_name_port_t object',
112        'memory_object_offset_t offset',
113        'boolean_t copy',
114        'vm_prot_t cur_protection',
115        'vm_prot_t max_protection',
116        'vm_inherit_t inheritance',
117      },
118    },
119    { number = 16, name = 'mach_port_allocate',
120      arguments = {
121        'mach_port_name_t target',
122        'mach_port_right_t right',
123        'mach_port_name_t *name',
124      },
125    },
126
127    { number = 18, name = 'mach_port_deallocate',
128      arguments = {
129        'mach_port_name_t target',
130        'mach_port_name_t name',
131      },
132    },
133    { number = 19, name = 'mach_port_mod_refs',
134      arguments = {
135        'mach_port_name_t target',
136        'mach_port_name_t name',
137        'mach_port_right_t right',
138        'mach_port_delta_t delta',
139      },
140    },
141    { number = 20, name = 'mach_port_move_member',
142      arguments = {
143        'mach_port_name_t target',
144        'mach_port_name_t member',
145        'mach_port_name_t after',
146      },
147    },
148    { number = 21, name = 'mach_port_insert_right',
149      arguments = {
150        'mach_port_name_t target',
151        'mach_port_name_t name',
152        'mach_port_name_t poly',
153        'mach_msg_type_name_t polyPoly',
154      },
155    },
156    { number = 22, name = 'mach_port_insert_member',
157      arguments = {
158        'mach_port_name_t target',
159        'mach_port_name_t name',
160        'mach_port_name_t pset',
161      },
162    },
163    { number = 23, name = 'mach_port_extract_member',
164      arguments = {
165        'mach_port_name_t target',
166        'mach_port_name_t name',
167        'mach_port_name_t pset',
168      },
169    },
170    { number = 24, name = 'mach_port_construct',
171      arguments = {
172        'mach_port_name_t target',
173        'mach_port_options_t *options',
174        'uint64_t context',
175        'mach_port_name_t *name',
176      },
177    },
178    { number = 25, name = 'mach_port_destruct',
179      arguments = {
180        'mach_port_name_t target',
181        'mach_port_name_t name',
182        'mach_port_delta_t srdelta',
183        'uint64_t guard',
184      },
185    },
186    { number = 26, name = 'mach_reply_port',
187      arguments = { 'void' },
188    },
189    { number = 27, name = 'thread_self',
190      arguments = { 'void' },
191    },
192    { number = 28, name = 'task_self',
193      arguments = { 'void' },
194    },
195    { number = 29, name = 'host_self',
196      arguments = { 'void' },
197    },
198
199    { number = 31, name = 'mach_msg',
200      arguments = {
201        'mach_msg_header_t *msg',
202        'mach_msg_option_t option',
203        'mach_msg_size_t send_size',
204        'mach_msg_size_t rcv_size',
205        'mach_port_name_t rcv_name',
206        'mach_msg_timeout_t timeout',
207        'mach_port_name_t notify',
208      },
209    },
210    { number = 32, name = 'mach_msg_overwrite',
211      arguments = {
212        'mach_msg_header_t *msg',
213        'mach_msg_option_t option',
214        'mach_msg_size_t send_size',
215        'mach_msg_size_t rcv_size',
216        'mach_port_name_t rcv_name',
217        'mach_msg_timeout_t timeout',
218        'mach_port_name_t notify',
219        'mach_msg_header_t *rcv_msg',
220        'mach_msg_size_t rcv_limit',
221      },
222    },
223    { number = 33, name = 'semaphore_signal',
224      arguments = {
225        'mach_port_name_t signal_name',
226      },
227    },
228    { number = 34, name = 'semaphore_signal_all',
229      arguments = {
230        'mach_port_name_t signal_name',
231      },
232    },
233    { number = 35, name = 'semaphore_signal_thread',
234      arguments = {
235        'mach_port_name_t signal_name',
236        'mach_port_name_t thread_name',
237      },
238    },
239    { number = 36, name = 'semaphore_wait',
240      arguments = {
241        'mach_port_name_t wait_name',
242      },
243    },
244    { number = 37, name = 'semaphore_wait_signal',
245      arguments = {
246        'mach_port_name_t wait_name',
247        'mach_port_name_t signal_name',
248      },
249    },
250    { number = 38, name = 'semaphore_timedwait',
251      arguments = {
252        'mach_port_name_t wait_name',
253        'unsigned int sec',
254        'clock_res_t nsec',
255      },
256    },
257    { number = 39, name = 'semaphore_timedwait_signal',
258      arguments = {
259        'mach_port_name_t wait_name',
260        'mach_port_name_t signal_name',
261        'unsigned int sec',
262        'clock_res_t nsec',
263      },
264    },
265    { number = 40, name = 'mach_port_get_attributes',
266      arguments = {
267        'mach_port_name_t target',
268        'mach_port_name_t name',
269        'mach_port_flavor_t flavor',
270        'mach_port_info_t port_info_out',
271        'mach_msg_type_number_t *port_info_outCnt',
272      },
273    },
274    { number = 41, name = 'mach_port_guard',
275      arguments = {
276        'mach_port_name_t target',
277        'mach_port_name_t name',
278        'uint64_t guard',
279        'boolean_t strict',
280      },
281    },
282    { number = 42, name = 'mach_port_unguard',
283      arguments = {
284        'mach_port_name_t target',
285        'mach_port_name_t name',
286        'uint64_t guard',
287      },
288    },
289    { number = 43, name = 'mach_generate_activity_id',
290      arguments = {
291        'mach_port_name_t target',
292        'int count',
293        'uint64_t *activity_id',
294      },
295    },
296    { number = 44, name = 'task_name_for_pid',
297      arguments = {
298        'mach_port_name_t target_tport',
299        'int pid',
300        'mach_port_name_t *tn',
301      },
302    },
303    { number = 45, name = 'task_for_pid',
304      arguments = {
305        'mach_port_name_t target_tport',
306        'int pid',
307        'mach_port_name_t *t',
308      },
309    },
310    { number = 46, name = 'pid_for_task',
311      arguments = {
312        'mach_port_name_t t',
313        'int *x',
314      },
315    },
316    { number = 47, name = 'mach_msg2',
317      arguments = {
318        'void *data',
319        'mach_msg_option64_t option64',
320        'mach_msg_header_t header',
321        'mach_msg_size_t send_size',
322        'mach_msg_size_t rcv_size',
323        'mach_port_t rcv_name',
324        'uint64_t timeout',
325        'uint32_t priority',
326      },
327    },
328    { number = 48, name = 'macx_swapon',
329      arguments = {
330        'uint64_t filename',
331        'int flags',
332        'int size',
333        'int priority',
334      },
335    },
336    { number = 49, name = 'macx_swapoff',
337      arguments = {
338        'uint64_t filename',
339        'int flags',
340      },
341    },
342    { number = 50, name = 'thread_get_special_reply_port',
343      arguments = { 'void' },
344    },
345    { number = 51, name = 'macx_triggers',
346      arguments = {
347        'int hi_water',
348        'int low_water',
349        'int flags',
350        'mach_port_t alert_port',
351      },
352    },
353    { number = 52, name = 'macx_backing_store_suspend',
354      arguments = {
355        'boolean_t suspend',
356      },
357    },
358    { number = 53, name = 'macx_backing_store_recovery',
359      arguments = {
360        'int pid',
361      },
362    },
363
364    { number = 58, name = 'pfz_exit',
365      arguments = { 'void' },
366    },
367    { number = 59, name = 'swtch_pri',
368      arguments = {
369        'int pri',
370      },
371    },
372    { number = 60, name = 'swtch',
373      arguments = { 'void' },
374    },
375    { number = 61, name = 'thread_switch',
376      arguments = {
377        'mach_port_name_t thread_name',
378        'int option',
379        'mach_msg_timeout_t option_time',
380      },
381    },
382    { number = 62, name = 'clock_sleep',
383      arguments = {
384        'mach_port_name_t clock_name',
385        'sleep_type_t sleep_type',
386        'int sleep_sec',
387        'int sleep_nsec',
388        'mach_timespec_t *wakeup_time',
389      },
390    },
391
392    { number = 70, name = 'host_create_mach_voucher',
393      arguments = {
394        'mach_port_name_t host',
395        'mach_voucher_attr_raw_recipe_array_t recipes',
396        'int recipes_size',
397        'mach_port_name_t *voucher',
398      },
399    },
400
401    { number = 72, name = 'mach_voucher_extract_attr_recipe',
402      arguments = {
403        'mach_port_name_t voucher_name',
404        'mach_voucher_attr_key_t key',
405        'mach_voucher_attr_raw_recipe_t recipe',
406        'mach_msg_type_number_t *recipe_size',
407      },
408    },
409
410    { number = 76, name = 'mach_port_type',
411      arguments = {
412        'ipc_space_t task',
413        'mach_port_name_t name',
414        'mach_port_type_t *ptype',
415      },
416    },
417    { number = 77, name = 'mach_port_request_notification',
418      arguments = {
419        'ipc_space_t task',
420        'mach_port_name_t name',
421        'mach_msg_id_t msgid',
422        'mach_port_mscount_t sync',
423        'mach_port_name_t notify',
424        'mach_msg_type_name_t notifyPoly',
425        'mach_port_name_t *previous',
426      },
427    },
428    { number = 88, name = 'exclaves_ctl',
429      arguments = {
430        'mach_port_name_t name',
431        'uint32_t operation_and_flags',
432        'uint64_t identifier',
433        'mach_vm_address_t buffer',
434        'mach_vm_size_t size',
435        'mach_vm_size_t size2',
436        'mach_vm_size_t offset',
437      },
438    },
439
440    { number = 89, name = 'mach_timebase_info',
441      arguments = {
442        'mach_timebase_info_t info',
443      },
444    },
445    { number = 90, name = 'mach_wait_until',
446      arguments = {
447        'uint64_t deadline',
448      },
449    },
450    { number = 91, name = 'mk_timer_create',
451      arguments = { 'void' },
452    },
453    { number = 92, name = 'mk_timer_destroy',
454      arguments = {
455        'mach_port_name_t name',
456      },
457    },
458    { number = 93, name = 'mk_timer_arm',
459      arguments = {
460        'mach_port_name_t name',
461        'uint64_t expire_time',
462      },
463    },
464    { number = 94, name = 'mk_timer_cancel',
465      arguments = {
466        'mach_port_name_t name',
467        'uint64_t *result_time',
468      },
469    },
470    { number = 95, name = 'mk_timer_arm_leeway',
471      arguments = {
472        'mach_port_name_t name',
473        'uint64_t mk_timer_flags',
474        'uint64_t mk_timer_expire_time',
475        'uint64_t mk_timer_leeway',
476      },
477    },
478    { number = 96, name = 'debug_control_port_for_pid',
479      arguments = {
480        'mach_port_name_t target_tport',
481        'int pid',
482        'mach_port_name_t *t',
483      },
484    },
485
486    { number = 100, name = 'iokit_user_client',
487      arguments = {
488        'void *userClientRef',
489        'uint32_t index',
490        'void *p1',
491        'void *p2',
492        'void *p3',
493        'void *p4',
494        'void *p5',
495        'void *p6',
496      },
497    },
498  },
499}
500
501-- Basic sanity checking that the same number isn't claimed by two syscalls.
502for type, entries in pairs(syscalls) do
503  local numbers_seen = {}
504  for _, call in ipairs(entries) do
505    if numbers_seen[call.number] then
506      io.stderr:write(('error: %s: saw %d twice: %s and %s\n'):format(type,
507          call.number, call.name, numbers_seen[call.number]))
508      os.exit(1)
509    end
510    numbers_seen[call.number] = call.name
511  end
512end
513
514print(cjson.encode(syscalls))
515