From 612b9f4da1a682eeb4947e473199c5231ae10be0 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 12 Dec 2022 00:13:37 +0100 Subject: [PATCH] darwin: add defs and funcs for Mach exception handling --- lib/std/c/darwin.zig | 108 +++++++++++++++++++++++++++++++++++ lib/std/c/darwin/aarch64.zig | 20 +++++++ lib/std/c/darwin/x86_64.zig | 27 +++++++++ lib/std/os/darwin.zig | 61 ++++++++++++++++++++ 4 files changed, 216 insertions(+) diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 51c5068614..0ace5f5067 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -15,6 +15,86 @@ const arch_bits = switch (native_arch) { else => struct {}, }; +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_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_MASK_MACHINE = arch_bits.EXC_MASK_MACHINE; + +pub const EXC_MASK_ALL = EXC_MASK_BAD_ACCESS | + EXC_MASK_BAD_INSTRUCTION | + EXC_MASK_ARITHMETIC | + EXC_MASK_EMULATION | + EXC_MASK_SOFTWARE | + EXC_MASK_BREAKPOINT | + EXC_MASK_SYSCALL | + EXC_MASK_MACH_SYSCALL | + EXC_MASK_RPC_ALERT | + EXC_MASK_RESOURCE | + EXC_MASK_GUARD | + EXC_MASK_MACHINE; + +/// Send a catch_exception_raise message including the identity. +pub const EXCEPTION_DEFAULT = 1; +/// Send a catch_exception_raise_state message including the +/// thread state. +pub const EXCEPTION_STATE = 2; +/// Send a catch_exception_raise_state_identity message including +/// the thread identity and state. +pub const EXCEPTION_STATE_IDENTITY = 3; +/// Send a catch_exception_raise_identity_protected message including protected task +/// and thread identity. +pub const EXCEPTION_IDENTITY_PROTECTED = 4; +/// Prefer sending a catch_exception_raice_backtrace message, if applicable. +pub const MACH_EXCEPTION_BACKTRACE_PREFERRED = 0x20000000; +/// include additional exception specific errors, not used yet. +pub const MACH_EXCEPTION_ERRORS = 0x40000000; +/// Send 64-bit code and subcode in the exception header */ +pub const MACH_EXCEPTION_CODES = 0x80000000; + +pub const MACH_EXCEPTION_MASK = MACH_EXCEPTION_CODES | + MACH_EXCEPTION_ERRORS | + MACH_EXCEPTION_BACKTRACE_PREFERRED; + pub const ucontext_t = extern struct { onstack: c_int, sigmask: sigset_t, @@ -166,6 +246,17 @@ pub const mach_vm_size_t = u64; pub const mach_msg_type_number_t = natural_t; pub const mach_msg_type_name_t = u32; pub const mach_port_right_t = natural_t; +pub const task_t = mach_port_t; +pub const exception_mask_t = u32; +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_array_t = [*]exception_behavior_t; +pub const thread_state_flavor_t = i32; pub const ipc_space_t = mach_port_t; pub const ipc_space_port_t = ipc_space_t; @@ -218,6 +309,23 @@ pub fn mach_task_self() callconv(.C) mach_port_t { return mach_task_self_; } +pub extern "c" fn task_get_exception_ports( + task: task_t, + exception_mask: exception_mask_t, + masks: exception_mask_array_t, + masks_cnt: *mach_msg_type_number_t, + old_handlers: exception_handler_array_t, + old_behaviors: exception_behavior_array_t, + old_flavors: exception_flavor_array_t, +) kern_return_t; +pub extern "c" fn task_set_exception_ports( + task: task_t, + exception_mask: exception_mask_t, + new_port: mach_port_t, + behavior: exception_behavior_t, + new_flavor: thread_state_flavor_t, +) kern_return_t; + pub const task_read_t = mach_port_t; pub extern "c" fn task_resume(target_task: task_read_t) kern_return_t; diff --git a/lib/std/c/darwin/aarch64.zig b/lib/std/c/darwin/aarch64.zig index 70153b5dfb..48b03363a1 100644 --- a/lib/std/c/darwin/aarch64.zig +++ b/lib/std/c/darwin/aarch64.zig @@ -16,3 +16,23 @@ pub const thread_state = extern struct { cpsr: u32, // Current program status register __pad: u32, }; + +pub const EXC_TYPES_COUNT = 14; +pub const EXC_MASK_MACHINE = 0; + +pub const ARM_THREAD_STATE = 1; +pub const ARM_UNIFIED_THREAD_STATE = ARM_THREAD_STATE; +pub const ARM_VFP_STATE = 2; +pub const ARM_EXCEPTION_STATE = 3; +pub const ARM_DEBUG_STATE = 4; +pub const THREAD_STATE_NONE = 5; +pub const ARM_THREAD_STATE64 = 6; +pub const ARM_EXCEPTION_STATE64 = 7; +pub const ARM_THREAD_STATE_LAST = 8; +pub const ARM_THREAD_STATE32 = 9; +pub const ARM_DEBUG_STATE32 = 14; +pub const ARM_DEBUG_STATE64 = 15; +pub const ARM_NEON_STATE = 16; +pub const ARM_NEON_STATE64 = 17; +pub const ARM_CPMU_STATE64 = 18; +pub const ARM_PAGEIN_STATE = 27; diff --git a/lib/std/c/darwin/x86_64.zig b/lib/std/c/darwin/x86_64.zig index 3d38d34d36..c7671bc23a 100644 --- a/lib/std/c/darwin/x86_64.zig +++ b/lib/std/c/darwin/x86_64.zig @@ -33,3 +33,30 @@ pub const thread_state = extern struct { pub const THREAD_STATE = 4; pub const THREAD_STATE_COUNT: c.mach_msg_type_number_t = @sizeOf(thread_state) / @sizeOf(c_int); + +pub const EXC_TYPES_COUNT = 14; +pub const EXC_MASK_MACHINE = 0; + +pub const x86_THREAD_STATE32 = 1; +pub const x86_FLOAT_STATE32 = 2; +pub const x86_EXCEPTION_STATE32 = 3; +pub const x86_THREAD_STATE64 = 4; +pub const x86_FLOAT_STATE64 = 5; +pub const x86_EXCEPTION_STATE64 = 6; +pub const x86_THREAD_STATE = 7; +pub const x86_FLOAT_STATE = 8; +pub const x86_EXCEPTION_STATE = 9; +pub const x86_DEBUG_STATE32 = 10; +pub const x86_DEBUG_STATE64 = 11; +pub const x86_DEBUG_STATE = 12; +pub const THREAD_STATE_NONE = 13; +pub const x86_AVX_STATE32 = 16; +pub const x86_AVX_STATE64 = (x86_AVX_STATE32 + 1); +pub const x86_AVX_STATE = (x86_AVX_STATE32 + 2); +pub const x86_AVX512_STATE32 = 19; +pub const x86_AVX512_STATE64 = (x86_AVX512_STATE32 + 1); +pub const x86_AVX512_STATE = (x86_AVX512_STATE32 + 2); +pub const x86_PAGEIN_STATE = 22; +pub const x86_THREAD_FULL_STATE64 = 23; +pub const x86_INSTRUCTION_STATE = 24; +pub const x86_LAST_BRANCH_STATE = 25; diff --git a/lib/std/os/darwin.zig b/lib/std/os/darwin.zig index 717eef0736..ab68554bdb 100644 --- a/lib/std/os/darwin.zig +++ b/lib/std/os/darwin.zig @@ -60,6 +60,67 @@ const mach_task = if (builtin.target.isDarwin()) struct { } } + pub const PortInfo = struct { + mask: std.c.exception_mask_t, + masks: [std.c.EXC_TYPES_COUNT]std.c.exception_mask_t, + ports: [std.c.EXC_TYPES_COUNT]std.c.mach_port_t, + behaviors: [std.c.EXC_TYPES_COUNT]std.c.exception_behavior_t, + flavors: [std.c.EXC_TYPES_COUNT]std.c.thread_state_flavor_t, + count: std.c.mach_msg_type_number_t, + }; + + pub fn getExceptionPorts(self: MachTask, mask: std.c.exception_mask_t) !PortInfo { + var info = PortInfo{ + .mask = mask, + .masks = undefined, + .ports = undefined, + .behaviors = undefined, + .flavors = undefined, + .count = 0, + }; + info.count = info.ports.len / @sizeOf(std.c.mach_port_t); + + switch (std.c.getKernError(std.c.task_get_exception_ports( + self.port, + info.mask, + &info.masks, + &info.count, + &info.ports, + &info.behaviors, + &info.flavors, + ))) { + .SUCCESS => return info, + .FAILURE => return error.PermissionDenied, + else => |err| { + log.err("task_get_exception_ports kernel call failed with error code: {s}", .{@tagName(err)}); + return error.Unexpected; + }, + } + } + + pub fn setExceptionPorts( + self: MachTask, + mask: std.c.exception_mask_t, + new_port: MachTask, + behavior: std.c.exception_behavior_t, + new_flavor: std.c.thread_state_flavor_t, + ) !void { + switch (std.c.getKernError(std.c.task_set_exception_ports( + self.port, + mask, + new_port.port, + behavior, + new_flavor, + ))) { + .SUCCESS => return, + .FAILURE => return error.PermissionDenied, + else => |err| { + log.err("task_set_exception_ports kernel call failed with error code: {s}", .{@tagName(err)}); + return error.Unexpected; + }, + } + } + pub const RegionInfo = struct { pub const Tag = enum { basic,