diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 0ace5f5067..817b7a18d6 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -18,46 +18,51 @@ const arch_bits = switch (native_arch) { pub const EXC_TYPES_COUNT = arch_bits.EXC_TYPES_COUNT; pub const THREAD_STATE_NONE = arch_bits.THREAD_STATE_NONE; -/// Could not access memory -pub const EXC_BAD_ACCESS = 1; -/// Instruction failed -pub const EXC_BAD_INSTRUCTION = 2; -/// Arithmetic exception -pub const EXC_ARITHMETIC = 3; -/// Emulation instruction -pub const EXC_EMULATION = 4; -/// Software generated exception -pub const EXC_SOFTWARE = 5; -/// Trace, breakpoint, etc. -pub const EXC_BREAKPOINT = 6; -/// System calls. -pub const EXC_SYSCALL = 7; -/// Mach system calls. -pub const EXC_MACH_SYSCALL = 8; -/// RPC alert -pub const EXC_RPC_ALERT = 9; -/// Abnormal process exit -pub const EXC_CRASH = 10; -/// Hit resource consumption limit -pub const EXC_RESOURCE = 11; -/// Violated guarded resource protections -pub const EXC_GUARD = 12; -/// Abnormal process exited to corpse state -pub const EXC_CORPSE_NOTIFY = 13; +pub const EXC = enum(exception_type_t) { + NULL = 0, + /// Could not access memory + BAD_ACCESS = 1, + /// Instruction failed + BAD_INSTRUCTION = 2, + /// Arithmetic exception + ARITHMETIC = 3, + /// Emulation instruction + EMULATION = 4, + /// Software generated exception + SOFTWARE = 5, + /// Trace, breakpoint, etc. + BREAKPOINT = 6, + /// System calls. + SYSCALL = 7, + /// Mach system calls. + MACH_SYSCALL = 8, + /// RPC alert + RPC_ALERT = 9, + /// Abnormal process exit + CRASH = 10, + /// Hit resource consumption limit + RESOURCE = 11, + /// Violated guarded resource protections + GUARD = 12, + /// Abnormal process exited to corpse state + CORPSE_NOTIFY = 13, +}; -pub const EXC_MASK_BAD_ACCESS = 1 << EXC_BAD_ACCESS; -pub const EXC_MASK_BAD_INSTRUCTION = 1 << EXC_BAD_INSTRUCTION; -pub const EXC_MASK_ARITHMETIC = 1 << EXC_ARITHMETIC; -pub const EXC_MASK_EMULATION = 1 << EXC_EMULATION; -pub const EXC_MASK_SOFTWARE = 1 << EXC_SOFTWARE; -pub const EXC_MASK_BREAKPOINT = 1 << EXC_BREAKPOINT; -pub const EXC_MASK_SYSCALL = 1 << EXC_SYSCALL; -pub const EXC_MASK_MACH_SYSCALL = 1 << EXC_MACH_SYSCALL; -pub const EXC_MASK_RPC_ALERT = 1 << EXC_RPC_ALERT; -pub const EXC_MASK_CRASH = 1 << EXC_CRASH; -pub const EXC_MASK_RESOURCE = 1 << EXC_RESOURCE; -pub const EXC_MASK_GUARD = 1 << EXC_GUARD; -pub const EXC_MASK_CORPSE_NOTIFY = 1 << EXC_CORPSE_NOTIFY; +pub const EXC_SOFT_SIGNAL = 0x10003; + +pub const EXC_MASK_BAD_ACCESS = 1 << @enumToInt(EXC.BAD_ACCESS); +pub const EXC_MASK_BAD_INSTRUCTION = 1 << @enumToInt(EXC.BAD_INSTRUCTION); +pub const EXC_MASK_ARITHMETIC = 1 << @enumToInt(EXC.ARITHMETIC); +pub const EXC_MASK_EMULATION = 1 << @enumToInt(EXC.EMULATION); +pub const EXC_MASK_SOFTWARE = 1 << @enumToInt(EXC.SOFTWARE); +pub const EXC_MASK_BREAKPOINT = 1 << @enumToInt(EXC.BREAKPOINT); +pub const EXC_MASK_SYSCALL = 1 << @enumToInt(EXC.SYSCALL); +pub const EXC_MASK_MACH_SYSCALL = 1 << @enumToInt(EXC.MACH_SYSCALL); +pub const EXC_MASK_RPC_ALERT = 1 << @enumToInt(EXC.RPC_ALERT); +pub const EXC_MASK_CRASH = 1 << @enumToInt(EXC.CRASH); +pub const EXC_MASK_RESOURCE = 1 << @enumToInt(EXC.RESOURCE); +pub const EXC_MASK_GUARD = 1 << @enumToInt(EXC.GUARD); +pub const EXC_MASK_CORPSE_NOTIFY = 1 << @enumToInt(EXC.CORPSE_NOTIFY); pub const EXC_MASK_MACHINE = arch_bits.EXC_MASK_MACHINE; pub const EXC_MASK_ALL = EXC_MASK_BAD_ACCESS | @@ -95,6 +100,44 @@ pub const MACH_EXCEPTION_MASK = MACH_EXCEPTION_CODES | MACH_EXCEPTION_ERRORS | MACH_EXCEPTION_BACKTRACE_PREFERRED; +pub const TASK_NULL: task_t = 0; +pub const THREAD_NULL: thread_t = 0; + +pub const MACH_MSG_OPTION_NONE = 0x00000000; + +pub const MACH_SEND_MSG = 0x00000001; +pub const MACH_RCV_MSG = 0x00000002; + +pub const MACH_RCV_LARGE = 0x00000004; +pub const MACH_RCV_LARGE_IDENTITY = 0x00000008; + +pub const MACH_SEND_TIMEOUT = 0x00000010; +pub const MACH_SEND_OVERRIDE = 0x00000020; +pub const MACH_SEND_INTERRUPT = 0x00000040; +pub const MACH_SEND_NOTIFY = 0x00000080; +pub const MACH_SEND_ALWAYS = 0x00010000; +pub const MACH_SEND_FILTER_NONFATAL = 0x00010000; +pub const MACH_SEND_TRAILER = 0x00020000; +pub const MACH_SEND_NOIMPORTANCE = 0x00040000; +pub const MACH_SEND_NODENAP = MACH_SEND_NOIMPORTANCE; +pub const MACH_SEND_IMPORTANCE = 0x00080000; +pub const MACH_SEND_SYNC_OVERRIDE = 0x00100000; +pub const MACH_SEND_PROPAGATE_QOS = 0x00200000; +pub const MACH_SEND_SYNC_USE_THRPRI = MACH_SEND_PROPAGATE_QOS; +pub const MACH_SEND_KERNEL = 0x00400000; +pub const MACH_SEND_SYNC_BOOTSTRAP_CHECKIN = 0x00800000; + +pub const MACH_RCV_TIMEOUT = 0x00000100; +pub const MACH_RCV_NOTIFY = 0x00000000; +pub const MACH_RCV_INTERRUPT = 0x00000400; +pub const MACH_RCV_VOUCHER = 0x00000800; +pub const MACH_RCV_OVERWRITE = 0x00000000; +pub const MACH_RCV_GUARDED_DESC = 0x00001000; +pub const MACH_RCV_SYNC_WAIT = 0x00004000; +pub const MACH_RCV_SYNC_PEEK = 0x00008000; + +pub const MACH_MSG_STRICT_REPLY = 0x00000200; + pub const ucontext_t = extern struct { onstack: c_int, sigmask: sigset_t, @@ -235,6 +278,11 @@ pub extern "c" fn @"close$NOCANCEL"(fd: fd_t) c_int; pub extern "c" fn mach_host_self() mach_port_t; pub extern "c" fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t; +pub const exception_type_t = c_int; +pub const exception_data_type_t = integer_t; +pub const exception_data_t = ?*mach_exception_data_type_t; +pub const mach_exception_data_type_t = i64; +pub const mach_exception_data_t = ?*mach_exception_data_type_t; pub const vm_map_t = mach_port_t; pub const vm_map_read_t = mach_port_t; pub const vm_region_flavor_t = c_int; @@ -243,20 +291,27 @@ pub const vm_region_recurse_info_t = *c_int; pub const mach_vm_address_t = usize; pub const vm_offset_t = usize; pub const mach_vm_size_t = u64; +pub const mach_msg_bits_t = c_uint; +pub const mach_msg_id_t = integer_t; pub const mach_msg_type_number_t = natural_t; -pub const mach_msg_type_name_t = u32; +pub const mach_msg_type_name_t = c_uint; +pub const mach_msg_option_t = integer_t; +pub const mach_msg_size_t = natural_t; +pub const mach_msg_timeout_t = natural_t; pub const mach_port_right_t = natural_t; pub const task_t = mach_port_t; -pub const exception_mask_t = u32; +pub const thread_port_t = task_t; +pub const thread_t = thread_port_t; +pub const exception_mask_t = c_uint; pub const exception_mask_array_t = [*]exception_mask_t; pub const exception_handler_t = mach_port_t; pub const exception_handler_array_t = [*]exception_handler_t; pub const exception_port_t = exception_handler_t; pub const exception_port_array_t = exception_handler_array_t; pub const exception_flavor_array_t = [*]thread_state_flavor_t; -pub const exception_behavior_t = i32; +pub const exception_behavior_t = c_uint; pub const exception_behavior_array_t = [*]exception_behavior_t; -pub const thread_state_flavor_t = i32; +pub const thread_state_flavor_t = c_int; pub const ipc_space_t = mach_port_t; pub const ipc_space_port_t = ipc_space_t; @@ -309,6 +364,25 @@ pub fn mach_task_self() callconv(.C) mach_port_t { return mach_task_self_; } +pub extern "c" fn mach_msg( + msg: ?*mach_msg_header_t, + option: mach_msg_option_t, + send_size: mach_msg_size_t, + rcv_size: mach_msg_size_t, + rcv_name: mach_port_name_t, + timeout: mach_msg_timeout_t, + notify: mach_port_name_t, +) kern_return_t; + +pub const mach_msg_header_t = extern struct { + msgh_bits: mach_msg_bits_t, + msgh_size: mach_msg_size_t, + msgh_remote_port: mach_port_t, + msgh_local_port: mach_port_t, + msgh_voucher_port: mach_port_name_t, + msgh_id: mach_msg_id_t, +}; + pub extern "c" fn task_get_exception_ports( task: task_t, exception_mask: exception_mask_t, @@ -681,6 +755,30 @@ pub extern "c" fn task_info( task_info_out: task_info_t, task_info_outCnt: *mach_msg_type_number_t, ) kern_return_t; + +pub const mach_task_basic_info = extern struct { + /// Virtual memory size (bytes) + virtual_size: mach_vm_size_t, + + /// Resident memory size (bytes) + resident_size: mach_vm_size_t, + + /// Total user run time for terminated threads + user_time: time_value_t, + + /// Total system run time for terminated threads + system_time: time_value_t, + + /// Default policy for new threads + policy: policy_t, + + /// Suspend count for task + suspend_count: mach_vm_size_t, +}; + +pub const MACH_TASK_BASIC_INFO = 20; +pub const MACH_TASK_BASIC_INFO_COUNT: mach_msg_type_number_t = @sizeOf(mach_task_basic_info) / @sizeOf(natural_t); + pub extern "c" fn _host_page_size(task: mach_port_t, size: *vm_size_t) kern_return_t; pub extern "c" fn vm_deallocate(target_task: vm_map_t, address: vm_address_t, size: vm_size_t) kern_return_t; pub extern "c" fn vm_machine_attribute( @@ -2052,11 +2150,11 @@ pub const E = enum(u16) { }; pub fn getKernError(err: kern_return_t) KernE { - return @intToEnum(KernE, @truncate(u8, @intCast(usize, err))); + return @intToEnum(KernE, @truncate(u32, @intCast(usize, err))); } /// Kernel return values -pub const KernE = enum(u8) { +pub const KernE = enum(u32) { SUCCESS = 0, /// Specified address is not currently valid @@ -2275,6 +2373,104 @@ pub const KernE = enum(u8) { _, }; +pub const mach_msg_return_t = kern_return_t; + +pub fn getMachMsgError(err: mach_msg_return_t) MachMsgE { + return @intToEnum(MachMsgE, @truncate(u32, @intCast(usize, err))); +} + +/// All special error code bits defined below. +pub const MACH_MSG_MASK: u32 = 0x3e00; +/// No room in IPC name space for another capability name. +pub const MACH_MSG_IPC_SPACE: u32 = 0x2000; +/// No room in VM address space for out-of-line memory. +pub const MACH_MSG_VM_SPACE: u32 = 0x1000; +/// Kernel resource shortage handling out-of-line memory. +pub const MACH_MSG_IPC_KERNEL: u32 = 0x800; +/// Kernel resource shortage handling an IPC capability. +pub const MACH_MSG_VM_KERNEL: u32 = 0x400; + +/// Mach msg return values +pub const MachMsgE = enum(u32) { + SUCCESS = 0x00000000, + + /// Thread is waiting to send. (Internal use only.) + SEND_IN_PROGRESS = 0x10000001, + /// Bogus in-line data. + SEND_INVALID_DATA = 0x10000002, + /// Bogus destination port. + SEND_INVALID_DEST = 0x10000003, + /// Message not sent before timeout expired. + SEND_TIMED_OUT = 0x10000004, + /// Bogus voucher port. + SEND_INVALID_VOUCHER = 0x10000005, + /// Software interrupt. + SEND_INTERRUPTED = 0x10000007, + /// Data doesn't contain a complete message. + SEND_MSG_TOO_SMALL = 0x10000008, + /// Bogus reply port. + SEND_INVALID_REPLY = 0x10000009, + /// Bogus port rights in the message body. + SEND_INVALID_RIGHT = 0x1000000a, + /// Bogus notify port argument. + SEND_INVALID_NOTIFY = 0x1000000b, + /// Invalid out-of-line memory pointer. + SEND_INVALID_MEMORY = 0x1000000c, + /// No message buffer is available. + SEND_NO_BUFFER = 0x1000000d, + /// Send is too large for port + SEND_TOO_LARGE = 0x1000000e, + /// Invalid msg-type specification. + SEND_INVALID_TYPE = 0x1000000f, + /// A field in the header had a bad value. + SEND_INVALID_HEADER = 0x10000010, + /// The trailer to be sent does not match kernel format. + SEND_INVALID_TRAILER = 0x10000011, + /// The sending thread context did not match the context on the dest port + SEND_INVALID_CONTEXT = 0x10000012, + /// compatibility: no longer a returned error + SEND_INVALID_RT_OOL_SIZE = 0x10000015, + /// The destination port doesn't accept ports in body + SEND_NO_GRANT_DEST = 0x10000016, + /// Message send was rejected by message filter + SEND_MSG_FILTERED = 0x10000017, + + /// Thread is waiting for receive. (Internal use only.) + RCV_IN_PROGRESS = 0x10004001, + /// Bogus name for receive port/port-set. + RCV_INVALID_NAME = 0x10004002, + /// Didn't get a message within the timeout value. + RCV_TIMED_OUT = 0x10004003, + /// Message buffer is not large enough for inline data. + RCV_TOO_LARGE = 0x10004004, + /// Software interrupt. + RCV_INTERRUPTED = 0x10004005, + /// compatibility: no longer a returned error + RCV_PORT_CHANGED = 0x10004006, + /// Bogus notify port argument. + RCV_INVALID_NOTIFY = 0x10004007, + /// Bogus message buffer for inline data. + RCV_INVALID_DATA = 0x10004008, + /// Port/set was sent away/died during receive. + RCV_PORT_DIED = 0x10004009, + /// compatibility: no longer a returned error + RCV_IN_SET = 0x1000400a, + /// Error receiving message header. See special bits. + RCV_HEADER_ERROR = 0x1000400b, + /// Error receiving message body. See special bits. + RCV_BODY_ERROR = 0x1000400c, + /// Invalid msg-type specification in scatter list. + RCV_INVALID_TYPE = 0x1000400d, + /// Out-of-line overwrite region is not large enough + RCV_SCATTER_SMALL = 0x1000400e, + /// trailer type or number of trailer elements not supported + RCV_INVALID_TRAILER = 0x1000400f, + /// Waiting for receive with timeout. (Internal use only.) + RCV_IN_PROGRESS_TIMED = 0x10004011, + /// invalid reply port used in a STRICT_REPLY message + RCV_INVALID_REPLY = 0x10004012, +}; + pub const SIGSTKSZ = 131072; pub const MINSIGSTKSZ = 32768; diff --git a/lib/std/os/darwin.zig b/lib/std/os/darwin.zig index ab68554bdb..2b0d8c4c0b 100644 --- a/lib/std/os/darwin.zig +++ b/lib/std/os/darwin.zig @@ -401,6 +401,43 @@ const mach_task = if (builtin.target.isDarwin()) struct { }, } } + + pub fn basicTaskInfo(task: MachTask) MachError!std.c.mach_task_basic_info { + var info: std.c.mach_task_basic_info = undefined; + var count = std.c.MACH_TASK_BASIC_INFO_COUNT; + switch (std.c.getKernError(std.c.task_info( + task.port, + std.c.MACH_TASK_BASIC_INFO, + @ptrCast(std.c.task_info_t, &info), + &count, + ))) { + .SUCCESS => return info, + else => |err| { + log.err("task_info kernel call failed with error code: {s}", .{@tagName(err)}); + return error.Unexpected; + }, + } + } + + pub fn @"resume"(task: MachTask) MachError!void { + switch (std.c.getKernError(std.c.task_resume(task.port))) { + .SUCCESS => {}, + else => |err| { + log.err("task_resume kernel call failed with error code: {s}", .{@tagName(err)}); + return error.Unexpected; + }, + } + } + + pub fn @"suspend"(task: MachTask) MachError!void { + switch (std.c.getKernError(std.c.task_suspend(task.port))) { + .SUCCESS => {}, + else => |err| { + log.err("task_suspend kernel call failed with error code: {s}", .{@tagName(err)}); + return error.Unexpected; + }, + } + } }; pub fn machTaskForPid(pid: std.os.pid_t) MachError!MachTask {