Commit 612b9f4da1

Jakub Konka <kubkon@jakubkonka.com>
2022-12-12 00:13:37
darwin: add defs and funcs for Mach exception handling
1 parent 402dfb5
Changed files (4)
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;
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;
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;
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,