XXNU Source Handbook Offline reading instructions
Part 07 · Chapter 07.04

Mach traps: complete slot catalog and operation boundaries

Interface overview · Machine entry paths · IPC · VM

The common table has 128 slots, indexed 0–127. There are 62 potentially named operations: 60 unconditional named slots, slot 47 when __LP64__ || __arm64__, and slot 63 when __LP64__. Thus an LP64 build has 62 named/66 invalid entries; ARM64 without LP64 has 61/67; a build satisfying neither condition has 60/68. These are table counts, not a claim that every named operation performs useful work in every configuration. Four named backing-store interfaces are unconditional ENOTSUP stubs, and other handlers have configuration-dependent bodies. Table, table size and entry layout.

The catalog below preserves every slot, exact argument counts and mungers, kernel argument-field order/types, implementation location, and operation purpose. It is generated from this checkout by build_mach_trap_catalog.py, with curated descriptions checked against selected bodies. The machine-entry companion explains how a slot becomes an ARM64 negative selector or an x86 class/number, and why an invalid slot generally raises a syscall exception before kern_invalid() is invoked.

Complete table: all 128 slots

The ABI column is argument count / 32-bit word count / munger suffix exactly as stored in the table; — means no munger. port marks the table’s direct port-name return flag. Argument declarations below are kernel argument-structure fields, in order; a user_addr_t is a userspace pointer value, not a kernel pointer. Source links on slot numbers identify the exact table entries. Conditional alternatives are preserved rather than evaluated for this host.

Slots 0–31

Slot Handler and availability ABI Kernel argument fields Purpose and first implementation boundary
0 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
1 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
2 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
3 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
4 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
5 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
6 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
7 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
8 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
9 kern_invalid 0 / 0 / — none Reserved low numbers; not a Mach operation.
10 _kernelrpc_mach_vm_allocate_trap 4 / 5 / wwlw mach_port_name_t target, user_addr_t addr, mach_vm_size_ut size, int flags (structure) Allocate an anonymous region in the current task via mach_vm_allocate_external; address is copied in/out.
11 _kernelrpc_mach_vm_purgable_control_trap 4 / 5 / wlww mach_port_name_t target, mach_vm_offset_t address, vm_purgable_t control, user_addr_t state (structure) Get or change current-task purgeable state via mach_vm_purgable_control; GET accepts the current-task read capability.
12 _kernelrpc_mach_vm_deallocate_trap 3 / 5 / wll mach_port_name_t target, mach_vm_address_ut address, mach_vm_size_ut size (structure) Remove a current-task virtual range via mach_vm_deallocate_external.
13 task_dyld_process_info_notify_get_trap 2 / 4 / ll mach_vm_address_t names_addr, mach_vm_address_t names_count_addr (structure) Copy active dyld notifier send-right names into the current task; capacity/count and failure cleanup are explicit.
14 _kernelrpc_mach_vm_protect_trap 5 / 7 / wllww mach_port_name_t target, mach_vm_address_ut address, mach_vm_size_ut size, boolean_t set_maximum, vm_prot_ut new_protection (structure) Change current-task region protections via mach_vm_protect.
15 _kernelrpc_mach_vm_map_trap 6 / 8 / wwllww mach_port_name_t target, user_addr_t addr, mach_vm_size_ut size, mach_vm_offset_ut mask, int flags, vm_prot_ut cur_protection (structure) Restricted anonymous mapping via mach_vm_map_external with null object, zero object offset, no copy, maximum ALL, default inheritance.
16 _kernelrpc_mach_port_allocate_trap 3 / 3 / www mach_port_name_t target, mach_port_right_t right, user_addr_t name (structure) Allocate a named right in the current IPC space via mach_port_allocate; copy out its name.
17 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
18 _kernelrpc_mach_port_deallocate_trap 2 / 2 / ww mach_port_name_t target, mach_port_name_t name (structure) Drop a user reference through mach_port_deallocate in the current IPC space.
19 _kernelrpc_mach_port_mod_refs_trap 4 / 4 / wwww mach_port_name_t target, mach_port_name_t name, mach_port_right_t right, mach_port_delta_t delta (structure) Adjust selected right user-reference count via mach_port_mod_refs.
20 _kernelrpc_mach_port_move_member_trap 3 / 3 / www mach_port_name_t target, mach_port_name_t member, mach_port_name_t after (structure) Move a receive right between port sets via mach_port_move_member.
21 _kernelrpc_mach_port_insert_right_trap 4 / 4 / wwww mach_port_name_t target, mach_port_name_t name, mach_port_name_t poly, mach_msg_type_name_t polyPoly (structure) Insert a right; same-name MAKE_SEND/COPY_SEND has a fast path, otherwise copy in a right and destroy it if insertion fails.
22 _kernelrpc_mach_port_insert_member_trap 3 / 3 / www mach_port_name_t target, mach_port_name_t name, mach_port_name_t pset (structure) Add receive-right membership to a port set via mach_port_insert_member.
23 _kernelrpc_mach_port_extract_member_trap 3 / 3 / www mach_port_name_t target, mach_port_name_t name, mach_port_name_t pset (structure) Remove receive-right membership from a port set via mach_port_extract_member.
24 _kernelrpc_mach_port_construct_trap 4 / 5 / wwlw mach_port_name_t target, user_addr_t options, uint64_t context, user_addr_t name (structure) Copy in options, construct a port with context, and copy out its name.
25 _kernelrpc_mach_port_destruct_trap 4 / 5 / wwwl mach_port_name_t target, mach_port_name_t name, mach_port_delta_t srdelta, uint64_t guard (structure) Destruct a port with send-reference delta and guard through mach_port_destruct.
26 mach_reply_port 0 / 0 / —; port no consumed fields (structure) Allocate a receive right in the current space; return its name directly or MACH_PORT_NULL.
27 thread_self_trap 0 / 0 / —; port no consumed fields (structure) Obtain the current thread self send right and install/copy it out with immovable-right support.
28 task_self_trap 0 / 0 / —; port no consumed fields (structure) Obtain the current task self send right and install/copy it out with immovable-right support.
29 host_self_trap 0 / 0 / —; port no consumed fields (structure) Copy a send right for the current task's host port into its IPC space.
30 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
31 mach_msg_trap 7 / 7 / wwwwwww user_addr_t msg, mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_name_t rcv_name, mach_msg_timeout_t timeout, mach_msg_priority_t priority, user_addr_t rcv_msg (structure) Legacy combined message send/receive; sets rcv_msg to zero before the overwrite implementation.

Slots 32–63

Slot Handler and availability ABI Kernel argument fields Purpose and first implementation boundary
32 mach_msg_overwrite_trap 8 / 8 / wwwwwwww user_addr_t msg, mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_name_t rcv_name, mach_msg_timeout_t timeout, mach_msg_priority_t priority, user_addr_t rcv_msg (structure) Legacy message send/receive with separate receive buffer; IPC_HAS_LEGACY_MACH_MSG_TRAP body, otherwise KERN_NOT_SUPPORTED.
33 semaphore_signal_trap 1 / 1 / w mach_port_name_t signal_name (structure) Signal one semaphore waiter or increment availability through semaphore_signal_internal_trap.
34 semaphore_signal_all_trap 1 / 1 / w mach_port_name_t signal_name (structure) Wake all eligible semaphore waiters; semaphore object reference is released after the operation.
35 semaphore_signal_thread_trap 2 / 2 / ww mach_port_name_t signal_name, mach_port_name_t thread_name (structure) Signal a semaphore with a selected thread target; resolves both names and drops references.
36 semaphore_wait_trap 1 / 1 / w mach_port_name_t wait_name (structure) Wait on a semaphore; blocking completion may return through a continuation.
37 semaphore_wait_signal_trap 2 / 2 / ww mach_port_name_t wait_name, mach_port_name_t signal_name (structure) Wait on one semaphore while signaling another; coordinated wait/signal internal path.
38 semaphore_timedwait_trap 3 / 3 / www mach_port_name_t wait_name, unsigned int sec, clock_res_t nsec (structure) Semaphore wait with relative seconds/nanoseconds timeout converted to a deadline.
39 semaphore_timedwait_signal_trap 4 / 4 / wwww mach_port_name_t wait_name, mach_port_name_t signal_name, unsigned int sec, clock_res_t nsec (structure) Timed wait plus signal, using the same semaphore wait/signal internal machinery.
40 _kernelrpc_mach_port_get_attributes_trap 5 / 5 / wwwww mach_port_name_t target, mach_port_name_t name, mach_port_flavor_t flavor, user_addr_t info, user_addr_t count (structure) Read current-task port attributes; clamp count to generated reply capacity, zero temporary storage, copy count/data out.
41 _kernelrpc_mach_port_guard_trap 4 / 5 / wwlw mach_port_name_t target, mach_port_name_t name, uint64_t guard, boolean_t strict (structure) Guard a current-space port with a 64-bit context and strictness policy.
42 _kernelrpc_mach_port_unguard_trap 3 / 4 / wwl mach_port_name_t target, mach_port_name_t name, uint64_t guard (structure) Unguard a current-space port after guard validation.
43 mach_generate_activity_id 3 / 3 / www mach_port_name_t target, int count, user_addr_t activity_id (structure) Reserve one or more globally allocated activity IDs; validates count and copies the first ID out.
44 task_name_for_pid 3 / 3 / www mach_port_name_t target_tport, int pid, user_addr_t t (structure) Resolve PID to a task-name capability with BSD process/credential/MAC checks.
45 task_for_pid 3 / 3 / www mach_port_name_t target_tport, int pid, user_addr_t t (structure) Resolve PID to a task-control capability with process, credential, MAC, and task-access policy checks.
46 pid_for_task 2 / 2 / ww mach_port_name_t t, user_addr_t pid (structure) Convert a task port to its PID and copy the PID to userspace.
47 mach_msg2_trap; __LP64__ || __arm64__, otherwise invalid 8 / 16 / llllllll mach_vm_address_t data, mach_msg_option64_t options, uint64_t msgh_bits_and_send_size, uint64_t msgh_remote_and_local_port, uint64_t msgh_voucher_and_id, uint64_t desc_count_and_rcv_name, uint64_t rcv_size_and_priority, uint64_t timeout (structure) Current packed 64-bit message ABI; decode packed header/scalar fields and dispatch send/receive with message policy.
48 macx_swapon 4 / 5 / lwww uint64_t filename, int flags, int size, int priority (structure) Retained ABI stub: returns ENOTSUP; does not create a swap file in this checkout.
49 macx_swapoff 2 / 3 / lw uint64_t filename, int flags (structure) Retained ABI stub: returns ENOTSUP; does not remove a swap file in this checkout.
50 thread_get_special_reply_port 0 / 0 / —; port no consumed fields (structure) Unbind any prior user special reply port, allocate a new receive+send right, bind it to the thread, return name.
51 macx_triggers 4 / 4 / wwww int hi_water, int low_water, int flags, mach_port_t alert_port (structure) Only compaction enable/disable flags reach macx_backing_store_compaction; other requests return ENOTSUP.
52 macx_backing_store_suspend 1 / 1 / w boolean_t suspend (structure) Retained ABI stub: returns ENOTSUP.
53 macx_backing_store_recovery 1 / 1 / w int pid (structure) Retained ABI stub: returns ENOTSUP.
54 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
55 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
56 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
57 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
58 pfz_exit 0 / 0 / — no consumed fields (structure) No-op success body; pending AST work is picked up on kernel exit from the preemption-free region.
59 swtch_pri 0 / 0 / — int pri (structure) Yield with temporary priority depression; the historical priority argument is unused and table argc is zero.
60 swtch 0 / 0 / — no consumed fields (structure) Yield if scheduler policy says useful; boolean result reports whether yielding remains appropriate.
61 thread_switch 3 / 3 / www mach_port_name_t thread_name, int option, mach_msg_timeout_t option_time (structure) Scheduler-directed switch/yield with optional depression/wait and a thread hint; continuation path can discard the stack.
62 clock_sleep_trap 5 / 5 / wwwww mach_port_name_t clock_name, sleep_type_t sleep_type, int sleep_sec, int sleep_nsec, user_addr_t wakeup_time (structure) Clock-port sleep with absolute/relative clock time and wakeup-time copyout.
63 mach_vm_reclaim_update_kernel_accounting_trap; __LP64__, otherwise invalid 3 / 5 / wll mach_port_name_t target_task, user_addr_t bytes_reclaimed_out, user_addr_t next_deadline_out (structure) Current-task deferred-reclamation accounting update; CONFIG_DEFERRED_RECLAIM body or KERN_NOT_SUPPORTED.

Slots 64–95

Slot Handler and availability ABI Kernel argument fields Purpose and first implementation boundary
64 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
65 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
66 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
67 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
68 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
69 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
70 host_create_mach_voucher_trap 4 / 4 / wwww mach_port_name_t host, mach_voucher_attr_raw_recipe_array_t recipes, int recipes_size, user_addr_t voucher (structure) Copy raw recipes, create a voucher, export its send right, and copy its name to userspace.
71 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
72 mach_voucher_extract_attr_recipe_trap 4 / 4 / wwww mach_port_name_t voucher_name, mach_voucher_attr_key_t key, mach_voucher_attr_raw_recipe_t recipe, user_addr_t recipe_size (structure) Resolve a voucher, extract one raw attribute recipe into bounded temporary storage, then copy bytes/count out.
73 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
74 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
75 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
76 _kernelrpc_mach_port_type_trap 3 / 3 / wwww mach_port_name_t target, mach_port_right_t name, user_addr_t ptype (structure) Return current-space right type bits through mach_port_type and copyout.
77 _kernelrpc_mach_port_request_notification_trap 7 / 7 / wwwwwww mach_port_name_t target, mach_port_name_t name, mach_msg_id_t msgid, mach_port_mscount_t sync, mach_port_name_t notify, mach_msg_type_name_t notifyPoly, user_addr_t previous (structure) Register/change a notification using a send-once disposition; copy previous notification right back into the namespace.
78 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
79 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
80 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
81 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
82 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
83 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
84 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
85 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
86 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
87 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
88 _exclaves_ctl_trap 8 / 14 / wwllllll mach_port_name_t name, uint32_t operation_and_flags, uint64_t identifier, mach_vm_address_t buffer, mach_vm_size_t size, uint64_t param1, uint64_t param2, mach_vm_address_t status (structure) Exclaves operation multiplexer: privilege/config checks then resource, IPC, sensor, notification, and boot operations; disabled body returns KERN_NOT_SUPPORTED.
89 mach_timebase_info_trap 1 / 1 / w user_addr_t info (structure) Copy the absolute-time conversion numerator/denominator to userspace.
90 mach_wait_until_trap 1 / 2 / l uint64_t deadline (structure) Wait until an absolute-time deadline through assert_wait_deadline/thread_block; interruption maps to a Mach result.
91 mk_timer_create_trap 0 / 0 / —; port no consumed fields (structure) Allocate a timer object and receive-right port; return the name or MACH_PORT_NULL.
92 mk_timer_destroy_trap 1 / 1 / w mach_port_name_t name (structure) Destroy the named timer port with timer-object validation.
93 mk_timer_arm_trap 2 / 3 / wl mach_port_name_t name, uint64_t expire_time (structure) Arm a timer at an absolute deadline through mk_timer_arm_trap_internal.
94 mk_timer_cancel_trap 2 / 2 / ww mach_port_name_t name, user_addr_t result_time (structure) Cancel timer delivery and optionally copy out its previous deadline.
95 mk_timer_arm_leeway_trap 4 / 6 / wlll mach_port_name_t name, uint64_t mk_timer_flags, uint64_t expire_time, uint64_t mk_leeway (structure) Arm a timer with flags and leeway through mk_timer_arm_trap_internal.

Slots 96–127

Slot Handler and availability ABI Kernel argument fields Purpose and first implementation boundary
96 debug_control_port_for_pid 3 / 3 / www mach_port_name_t target_tport, int pid, user_addr_t t (structure) Obtain a task debug-control capability subject to process/credential/entitlement restrictions.
97 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
98 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
99 kern_invalid 0 / 0 / — none No operation assigned; dispatch rejects this slot.
100 iokit_user_client_trap 8 / 8 / wwwwwwww void * userClientRef, uint32_t index, void * p1, void * p2, void * p3, void * p4, void * p5, void * p6 (structure) Dispatch an IOKit user-client trap or DriverKit uext trap from a tagged reference; index and six scalars reach the selected target.
101 kern_invalid 0 / 0 / — none Reserved for IOKit; currently invalid.
102 kern_invalid 0 / 0 / — none Reserved for IOKit; currently invalid.
103 kern_invalid 0 / 0 / — none Reserved for IOKit; currently invalid.
104 kern_invalid 0 / 0 / — none Reserved for IOKit; currently invalid.
105 kern_invalid 0 / 0 / — none Reserved for IOKit; currently invalid.
106 kern_invalid 0 / 0 / — none Reserved for IOKit; currently invalid.
107 kern_invalid 0 / 0 / — none Reserved for IOKit; currently invalid.
108 kern_invalid 0 / 0 / — none Invalid despite the historical thread_set_x86_64_compat userspace stub.
109 kern_invalid 0 / 0 / — none Explicitly unused table slot.
110 kern_invalid 0 / 0 / — none Explicitly unused table slot.
111 kern_invalid 0 / 0 / — none Explicitly unused table slot.
112 kern_invalid 0 / 0 / — none Explicitly unused table slot.
113 kern_invalid 0 / 0 / — none Explicitly unused table slot.
114 kern_invalid 0 / 0 / — none Explicitly unused table slot.
115 kern_invalid 0 / 0 / — none Explicitly unused table slot.
116 kern_invalid 0 / 0 / — none Explicitly unused table slot.
117 kern_invalid 0 / 0 / — none Explicitly unused table slot.
118 kern_invalid 0 / 0 / — none Explicitly unused table slot.
119 kern_invalid 0 / 0 / — none Explicitly unused table slot.
120 kern_invalid 0 / 0 / — none Explicitly unused table slot.
121 kern_invalid 0 / 0 / — none Explicitly unused table slot.
122 kern_invalid 0 / 0 / — none Explicitly unused table slot.
123 kern_invalid 0 / 0 / — none Explicitly unused table slot.
124 kern_invalid 0 / 0 / — none Explicitly unused table slot.
125 kern_invalid 0 / 0 / — none Explicitly unused table slot.
126 kern_invalid 0 / 0 / — none Explicitly unused table slot.
127 kern_invalid 0 / 0 / — none Explicitly unused table slot.

ABI metadata and historical discrepancies

The table stores a function pointer, logical argument count, count of 32-bit words, optional 32-bit munger, and a flag for direct port-name results. Six entries set that result flag: 26, 27, 28, 29, 50, and 91. Dispatchers use it when converting policy denial to MACH_PORT_NULL. It does not mean every other handler returns a conventional kern_return_t: swtch returns a boolean, and the retained macx_* bodies use BSD-valued errors through a Mach-table route. Entry definition, filter return handling.

The kernel's argument structures are the decoder contract; library prototypes and assembly macros are additional evidence rather than substitutes. This matters in several visible cases:

Case Exact source distinction
mach_msg_trap, slot 31 Shares the overwrite argument structure but consumes seven table arguments; its body explicitly zeros rcv_msg before delegation.
mach_msg_overwrite_trap, slot 32 Kernel structure/table have eight consumed fields; the user prototype and historical stub also describe a ninth rcv_limit argument. The ARM stub comments explicitly say the ninth is unused.
swtch_pri, slot 59 Public prototype/argument structure contain pri, but the table argument count is zero and the body marks the argument structure unused.
mach_port_type, slot 76 Table records 3 / 3 / munge_wwww; the munger name is not a reason to silently rewrite the stored counts to four.
mk_timer_arm_leeway, slot 95 Table records four logical arguments and six 32-bit words with munge_wlll; the argument structure contains one port name plus three 64-bit fields, and the non-LP64 stub requests seven words. The catalog retains this mismatch.
VM map stub, slot 15 Historical stub macro requests nine words, while kernel table stores eight 32-bit words for six logical fields.
Compatibility stub, slot 108 thread_set_x86_64_compat is emitted by the common stub list, but the actual table entry is kern_invalid; its declaration is not evidence of an implemented operation.

The 32-bit munger bodies make the distinction concrete: munge_wwww widens four words, while munge_wlll reads its last 64-bit value beginning at input word five. Munger implementations, three-long form.

Sources: kernel message structures, stub list, unused ninth-argument comment, swtch body, slot 76, timer structure, timer/compatibility stubs. These are source observations, not fixes or claims that every compatibility path is exercised in a shipped build. Modern ARM64 argument gathering copies 64-bit slots; x86 retains both 64-bit gathering and a 32-bit copy/munge route. See machine entry points.

Current-task fast traps and MIG fallback

The _kernelrpc_*_trap family is not a general in-kernel MIG demultiplexer. Its handlers usually recognize a capability for the current task, then call a VM or IPC-space operation directly. An unsupported destination produces MACH_SEND_INVALID_DEST, allowing the library to choose its message-based _kernelrpc_* implementation. A real operation failure, such as invalid arguments or failed user copy, does not universally trigger the fallback. VM trap bodies, port trap bodies, message interface catalog.

current-task VM allocation fast path

_kernelrpc_mach_vm_allocate_trap(struct _kernelrpc_mach_vm_allocate_trap_args *args)
{
	mach_vm_offset_t addr;
	task_t task = port_name_to_current_task_noref(args->target);
	int rv = MACH_SEND_INVALID_DEST;

	if (task) {
		if ((rv = mach_copyin(args->addr, (char *)&addr, sizeof(addr)))) {
			goto done;
		}

		rv = mach_vm_allocate_external(task->map, &addr, args->size, args->flags);
		if (rv == KERN_SUCCESS) {
			rv = mach_copyout(&addr, args->addr, sizeof(addr));
		}
	}

done:
	return rv;
}

The corresponding library branch is equally specific:

VM allocation fallback condition

	rv = _kernelrpc_mach_vm_allocate_trap(target, address, size, flags);

	if (rv == MACH_SEND_INVALID_DEST) {
		rv = _kernelrpc_mach_vm_allocate(target, address, size, flags);
	}
Mach traps: complete slot catalog and operation boundaries diagram
Mach traps: complete slot catalog and operation boundaries diagram · Open SVG
Mermaid source
flowchart TD
    L["mach_vm_allocate / port wrapper"] --> T["direct trap"]
    T --> C{"current-task fast target accepted?"}
    C -->|yes| H["copy user inputs → VM / IPC implementation → copy outputs"]
    C -->|no| I["MACH_SEND_INVALID_DEST"]
    I --> G["library MIG client creates message"]
    G --> M["mach_msg transport trap"]
    M --> K["destination kobject / MIG routine dispatch"]
    H --> R["return operation result"]
Wrapper family Local selection / fallback rule
mach_vm_allocate, deallocate, protect, purgable_control Attempt direct trap; only MACH_SEND_INVALID_DEST selects the corresponding _kernelrpc_* message call. VM wrappers, purgeable wrapper.
mach_vm_map Attempt the restricted trap only for a null memory object, maximum protection VM_PROT_ALL, and default inheritance. Other mappings begin with the message fallback result; the full message interface carries object/offset/copy/max/inheritance fields absent from the trap. Mapping wrapper.
Port type/allocate/deallocate/mod-refs/membership/right insertion/attributes/guard/construct/destruct/notification Trap wrappers follow the same invalid-destination fallback pattern; operations without a trap, such as port rename, remain message interfaces. Port wrappers, notification/insertion, construct/guard wrappers.
Voucher creation/extraction Attempt recipe trap, then corresponding MIG routine on invalid destination. Host creation retains architecture-specific historical fallback checks. Host wrapper, recipe extraction.
Deferred reclamation accounting Userspace ring sampling calls the dedicated trap and updates its local accounting/deadline state; this body has no generic MIG fallback. Ring wrapper.

The fast-path scope has real ownership consequences. mach_port_insert_right uses a same-name MAKE_SEND/COPY_SEND shortcut; otherwise it copies in a right, converts the disposition, invokes insertion, and destroys the acquired right if insertion fails. Notification registration similarly converts/acquires a send-once right and may copy a previous notification right into the caller's space. A copyout error is later than the kernel object transition: allocation and port-construction bodies do not show a universal rollback of a successfully created object when the final scalar copyout fails. Right insertion cleanup, notification ownership, port construction, rights lifecycle.

Message transport, packed ABI, and interruption

Slot 47's eight logical arguments are eight 64-bit fields, with several packing two 32-bit values. The kernel reconstructs the message header from these scalars; descriptor/body data still comes from the user message or vectors. The ordinary nonvector interpretation is:

Packed argument Low 32 bits High 32 bits
msgh_bits_and_send_size Header bits Send byte count
msgh_remote_and_local_port Remote port Local port
msgh_voucher_and_id Voucher port Message ID
desc_count_and_rcv_name Descriptor count Receive port/set name
rcv_size_and_priority Receive size Priority / relevant send context

Vector mode changes how size/count fields are interpreted and obtains message/auxiliary vector information first. The kernel applies current-task options and ipc_preflight_msg_option64(), performs send if requested, and only proceeds to receive if send succeeded. A bad receive vector does not necessarily prevent a valid send in a combined operation. Packed decoding and send, message ownership guide.

header reconstruction from packed trap fields

		mach_msg_send_uctx_t send_uctx = {
			.send_header = {
				.msgh_bits         = (mach_msg_bits_t) (mb_ss),
				.msgh_size         = 0,
				.msgh_remote_port  = (mach_port_name_t)(mr_lp),
				.msgh_local_port   = (mach_port_name_t)(mr_lp >> 32),
				.msgh_voucher_port = (mach_port_name_t)(mv_id),
				.msgh_id           = (mach_msg_id_t)   (mv_id >> 32),
			},
			.send_dsc_count = (mach_msg_size_t)dc_rn,
		};

mach_msg2_internal() removes library-only option bits and retries an interrupted send when allowed. After an interrupted receive, it clears the send action and send size before retrying. Reissuing the original combined operation could otherwise resend a request whose send already completed. Library retry body, receive phase and compensation.

Slots 31 and 32 remain named on all table configurations, but their meaningful legacy body is selected by IPC_HAS_LEGACY_MACH_MSG_TRAP, defined here only for XNU_TARGET_OS_OSX. Otherwise the overwrite handler returns KERN_NOT_SUPPORTED; slot 31 delegates to it. Thus the count of installed function names is not the count of supported transports. Legacy configuration, disabled result.

Message IDs belong to a separate namespace. A request using slot 47 may target a user server, a kernel kobject, or another supported destination; only later IPC/kobject dispatch selects the appropriate service routine. The MIG catalog inventories those messages and generated/external boundaries. The transport trap number does not identify a particular MIG operation.

Semaphores, scheduler calls, and timer ports

The semaphore traps convert port names to retained semaphore objects before using the shared wait/signal machinery. A targeted signal also resolves and later releases a thread reference; a null target means “choose an existing waiter without pre-posting” in that particular operation. Timed waits validate the timespec; {0,0} selects nonblocking behavior rather than an arbitrary already-expired timestamp. Wait handlers supply thread_syscall_return as their continuation, so the blocked operation can complete without returning through its original C frame. Targeted signal, wait entry, timed-wait conversion, wait/turnstile mechanisms.

swtch and swtch_pri ask scheduler policy whether yielding is useful; swtch_pri adds temporary depression and removes it in its continuation. pfz_exit currently just succeeds: its purpose is to enter/exit the kernel so pending AST processing can run, not to invoke a hidden scheduler-specific handler in the trap body. thread_switch has a richer option/hint path. Yield operations, thread switch, scheduler guide.

Timer creation allocates a timer object, initializes a thread call, preallocates a reusable expiration message, and allocates a receive-right port carrying the timer label. The timer retains its own send right. Arming/canceling operate through this port identity; destruction validates the receive right and timer label. Final timer teardown coordinates with an active callback, so “cancel” and “destroy the port/object” are different lifetime operations. Creation, label deallocation, destroy, arm/cancel.

Exclaves slot 88: all 26 secondary operations

operation_and_flags uses the upper byte for the operation and the lower 24 bits for flags; this trap currently rejects nonzero flags. CONFIG_EXCLAVES == 0 leaves the slot present but returns KERN_NOT_SUPPORTED. With the feature enabled, the body applies operation-specific privilege checks, waits for ExclaveCore boot for the ordinary route, and interprets the other seven arguments according to the selected operation. Boot is handled by an earlier privilege-gated branch. Encoding enum/macros, entry privilege/configuration, disabled body.

The following table inventories every non-sentinel enum operation. Field names refer to the slot-88 kernel structure above; the local handler may rename identifier to an offset and param1/param2 to secondary lengths/offsets. These are operation-specific uses, not additional trap numbers.

Operation Main arguments and local implementation boundary
1 ENDPOINT_CALL Null name; identifier selects service; buffer/size hold an exact-size IPC buffer. Copy into per-thread IPC storage, check current-domain service availability, call endpoint, copy response out. Body.
2 NAMED_BUFFER_CREATE Identifier is a user string pointer; size and param1 select length/permissions; return resource port through buffer. Body.
3 NAMED_BUFFER_COPYIN Resource port name; buffer/size and identifier/param1/param2 select one/two copy ranges; retained shared-memory resource passed to copyin helper then released. Body.
4 NAMED_BUFFER_COPYOUT Corresponding shared-memory resource-to-user copy and release. Body.
5 BOOT Null name plus identifier/stage; privilege-gated operation_boot() before ordinary resource dispatch. Body.
6 LAUNCH_CONCLAVE Null name; ensure thread IPC buffer, call task_launch_conclave, then handle stop-upcall completion. Body.
7 LOOKUP_SERVICES Buffer/size describe resource lookup data; current body requires exactly one exclaves_resource_user request. Body.
8 AUDIO_BUFFER_CREATE Identifier string and size; map arbitrated audio-memory resource and return a port through buffer. Shared body.
9 AUDIO_BUFFER_COPYOUT Resource port, user buffer/ranges and status address; arbitrated-memory copyout helper. Shared body.
10 SENSOR_CREATE Identifier string; open sensor resource in current domain and export port through buffer. Body.
11 SENSOR_START Sensor port and identifier; call start helper, release resource, copy status through buffer. Body.
12 SENSOR_STOP Same shape with sensor stop helper. Body.
13 SENSOR_STATUS Same shape with status query helper. Body.
14 NOTIFICATION_RESOURCE_LOOKUP Exact resource-user structure in buffer; lookup notification, export port and metadata, undo exported right on output failure. Body.
15 AOE_SETUP Requires joined conclave; setup helper returns message/worker counts through buffer/status addresses. Body.
16 AOE_MESSAGE_LOOP Requires joined conclave; enter exclaves_aoe_message_loop(). Body.
17 AOE_WORK_LOOP Requires joined conclave; enter exclaves_aoe_work_loop(). Body.
18 SENSOR_MIN_ON_TIME Special privilege; null name and exact indicator-deadline structure copied in/out around deadline helper. Body.
19 ARBITRATED_BUFFER_CREATE Same shape as audio creation, selecting the non-audio arbitrated-memory type. Shared body.
20 ARBITRATED_BUFFER_COPYOUT Same arbitrated-resource copyout path as operation 9. Shared body.
21 DAEMON_NOTIFICATION_REGISTER Privileged caller; exact daemon-notification structure, copied send right, named resource lookup, retained resource plus port-list entry under resource mutex. Body.
22 DAEMON_NOTIFICATION_DEREGISTER Match translated send port in the resource list, remove entry, release send right and registration resource reference. Body.
23 AOE_ENUMERATE_AND_SETUP_SERVICES Null name/joined conclave; enumerate/setup and copy service count through buffer. Body.
24 AOE_GET_ALL_SERVICE_INFOS Null name/joined conclave; nonzero integral array of service-info structures, bounded count, helper plus copyout. Body.
25 AOE_MESSAGE_LOOP_WITH_SERVICE_ID Null name/joined conclave; service identifier passed in param1 to message-loop helper. Body.
26 AOE_WORK_LOOP_WITH_SERVICE_ID Same selection for work-loop helper. Body.

Operation zero, the LAST sentinel, and other unhandled selectors reach invalid-argument handling after the applicable front-end checks. The catalog establishes local argument roles and dispatch, not the secure service's complete implementation. Continue with Exclaves resources and secure execution for resource, thread, scheduler and external-boundary ownership.

IOKit, task access, and retained stubs

Slot 100 is a dispatch surface, not one universal driver operation. iokit_user_client_trap() interprets tagged reference bits, then either looks up a DriverKit uext reference and calls IOUserServerUEXTTrap, or resolves a current-task connection, applies an optional trap filter, and asks the user client for its target/trap at the supplied index. The six scalar payload arguments reach that selected member function. Lookup references are released by the appropriate path. The concrete target's index table remains provider-specific. IOKit trap body, DriverKit dispatch, user-client ownership.

PID/task conversion traps are implemented in BSD's process code even though they live in the Mach trap table. task_for_pid and debug-control access can obtain a task reference, drop a process reference before an access-server upcall, and apply credential/MAC/entitlement policy. A table slot or a PID is not authorization to receive a task-control right. pid_for_task consumes a task-name conversion and returns the PID through a userspace address; its body also handles a corpse task. Task-control entry, debug-control entry, PID conversion, process access policy.

Four historical macx_* handlers—swapon, swapoff, backing-store suspend and recovery—return ENOTSUP immediately. macx_triggers only supports compaction enable/disable flags via macx_backing_store_compaction(), whose disable behavior is further conditional on ARM64 macOS. Their old names/comments must not be used to document nonexistent modern swap-file operations. Stub/compaction bodies.

The deferred-reclamation accounting trap is installed only in LP64 table builds. In both feature configurations it first checks current-task identity and nonnull output addresses, returning MACH_SEND_INVALID_DEST or KERN_INVALID_ARGUMENT on those failures. After those checks, a build without CONFIG_DEFERRED_RECLAIM returns KERN_NOT_SUPPORTED. The enabled path invokes the accounting helper and attempts its two scalar copyouts only if that helper succeeds. It returns the helper's status rather than testing the copyout return values, so success cannot be read as a universal proof that both userspace outputs were written. Accounting trap.

Mach-named operations outside this table

mach_eventlink_signal, mach_eventlink_wait_until, and mach_eventlink_signal_wait_until are BSD slots 496, 497, and 498. The library explicitly explains the choice: these calls need a 64-bit register return containing count/result information, while ordinary Mach traps do not offer that result convention. The wrappers decode the error and, for wait operations, update the caller's count. Creation/association and other object operations can still be message interfaces. BSD declarations, library encoding boundary, BSD catalog, MIG catalog.

Likewise, direct ARM absolute/continuous-time selectors and x86 machine-dependent/diagnostic tables are cataloged in machine entry points, not counted as additional common Mach slots. A port's externalMethod selector, a voucher recipe command, and a MIG message ID are yet other namespaces selected after the top-level entry.

Inspection scope and regeneration

Area Work performed and limit
Shared table and ABI All 128 slots, both conditional alternatives, all 62 potential handler definitions, and their kernel argument structures were extracted. Munger spelling and count mismatches are preserved.
Current-task fast paths Read VM/port/voucher trap bodies and library fallback selectors, including rights transfer, bounded buffers and output-copy boundaries. Linked subsystem guides supply full lower-layer algorithms.
Message transport Read legacy feature gating, packed mach_msg2 decoding and send-before-receive boundary, plus library interruption loops. Full message ownership is in the IPC guide.
Blocking/time operations Read semaphore entry/reference/deadline paths, scheduler yield continuations, clock waits and timer creation/arm/cancel/destroy entry bodies. Not every scheduler/interleaving was re-audited.
Multiplexers and policy Read all Exclaves case boundaries and selected resource ownership branches, IOKit trap dispatch, task/PID access entry bodies, accounting and backing-store stubs. Secure service/driver implementations remain separate providers.
Validation python3 -B docs-ai/tools/build_mach_trap_catalog.py --check verifies the generated catalog against the source snapshot; the general documentation checker validates links and exact excerpts. No syscall execution, compatibility test, or kernel build was performed.

The generator updates only the marked all-slot table, preserving this explanatory material. Its purpose descriptions are curated from implementation bodies and must be reviewed if behavior changes; extraction is not semantic verification or a C preprocessor.

Search the handbook

Search every chapter, interface and code excerpt.

    Diagram

    Source preview

    Open full file