darwin: add defs and funcs for Mach exception handling

This commit is contained in:
Jakub Konka 2022-12-12 00:13:37 +01:00
parent 402dfb5fd3
commit 612b9f4da1
4 changed files with 216 additions and 0 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,