diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 3c133caadb..ec181c632f 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -155,6 +155,7 @@ 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; pub const vm_region_info_t = *c_int; +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; @@ -193,13 +194,20 @@ pub extern "c" fn mach_vm_region( info_cnt: *mach_msg_type_number_t, object_name: *mach_port_t, ) kern_return_t; - -pub const VM_REGION_BASIC_INFO_64 = 9; -pub const VM_REGION_SUBMAP_SHORT_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_info_64) / @sizeOf(natural_t); +pub extern "c" fn mach_vm_region_recurse( + target_task: vm_map_t, + address: *mach_vm_address_t, + size: *mach_vm_size_t, + nesting_depth: *natural_t, + info: vm_region_recurse_info_t, + info_cnt: *mach_msg_type_number_t, +) kern_return_t; pub const vm_inherit_t = u32; pub const memory_object_offset_t = u64; pub const vm_behavior_t = i32; +pub const vm32_object_id_t = u32; +pub const vm_object_id_t = u64; pub const VM_INHERIT_SHARE: vm_inherit_t = 0; pub const VM_INHERIT_COPY: vm_inherit_t = 1; @@ -221,8 +229,47 @@ pub const VM_BEHAVIOR_REUSE: vm_behavior_t = 9; pub const VM_BEHAVIOR_CAN_REUSE: vm_behavior_t = 10; pub const VM_BEHAVIOR_PAGEOUT: vm_behavior_t = 11; -pub const vm32_object_id_t = u32; -pub const vm_object_id_t = u64; +pub const VM_REGION_BASIC_INFO_64 = 9; +pub const VM_REGION_EXTENDED_INFO = 13; +pub const VM_REGION_TOP_INFO = 12; +pub const VM_REGION_SUBMAP_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_info_64) / @sizeOf(natural_t); +pub const VM_REGION_SUBMAP_SHORT_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_short_info_64) / @sizeOf(natural_t); +pub const VM_REGION_BASIC_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_basic_info_64) / @sizeOf(c_int); +pub const VM_REGION_EXTENDED_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_extended_info) / @sizeOf(natural_t); +pub const VM_REGION_TOP_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_top_info) / @sizeOf(natural_t); + +pub const vm_region_basic_info_64 = extern struct { + protection: vm_prot_t, + max_protection: vm_prot_t, + inheritance: vm_inherit_t, + shared: boolean_t, + reserved: boolean_t, + offset: memory_object_offset_t, + behavior: vm_behavior_t, + user_wired_count: u16, +}; + +pub const vm_region_extended_info = extern struct { + protection: vm_prot_t, + user_tag: u32, + pages_resident: u32, + pages_shared_now_private: u32, + pages_swapped_out: u32, + pages_dirtied: u32, + ref_count: u32, + shadow_depth: u16, + external_pager: u8, + share_mode: u8, + pages_reusable: u32, +}; + +pub const vm_region_top_info = extern struct { + obj_id: u32, + ref_count: u32, + private_pages_resident: u32, + shared_pages_resident: u32, + share_mode: u8, +}; pub const vm_region_submap_info_64 = extern struct { // present across protection @@ -262,6 +309,34 @@ pub const vm_region_submap_info_64 = extern struct { object_id_full: vm_object_id_t, }; +pub const vm_region_submap_short_info_64 = extern struct { + // present access protection + protection: vm_prot_t, + // max avail through vm_prot + max_protection: vm_prot_t, + // behavior of map/obj on fork + inheritance: vm_inherit_t, + // offset into object/map + offset: memory_object_offset_t, + // user tag on map entry + user_tag: u32, + // obj/map mappers, etc + ref_count: u32, + // only for obj + shadow_depth: u16, + // only for obj + external_pager: u8, + // see enumeration + share_mode: u8, + // submap vs obj + is_submap: boolean_t, + // access behavior hint + behavior: vm_behavior_t, + // obj/map name, not a handle + object_id: vm32_object_id_t, + user_wired_count: u16, +}; + pub const thread_act_t = mach_port_t; pub const thread_state_t = *natural_t; pub const mach_port_array_t = *mach_port_t; @@ -986,9 +1061,13 @@ pub const MAP = struct { }; pub const MSF = struct { - pub const ASYNC = 1; - pub const INVALIDATE = 2; - pub const SYNC = 4; + pub const ASYNC = 0x1; + pub const INVALIDATE = 0x2; + // invalidate, leave mapped + pub const KILLPAGES = 0x4; + // deactivate, leave mapped + pub const DEACTIVATE = 0x8; + pub const SYNC = 0x10; }; pub const SA = struct { diff --git a/lib/std/os/darwin.zig b/lib/std/os/darwin.zig index c44caf7343..96d43e4f8e 100644 --- a/lib/std/os/darwin.zig +++ b/lib/std/os/darwin.zig @@ -24,22 +24,63 @@ const mach_task = if (builtin.target.isDarwin()) struct { return self.port != 0; } - pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!std.c.vm_prot_t { - var base_addr = address; + pub const RegionInfo = struct { + pub const Tag = enum { + basic, + extended, + top, + }; + + base_addr: u64, + tag: Tag, + info: union { + basic: std.c.vm_region_basic_info_64, + extended: std.c.vm_region_extended_info, + top: std.c.vm_region_top_info, + }, + }; + + pub fn getRegionInfo( + task: MachTask, + address: u64, + len: usize, + tag: RegionInfo.Tag, + ) MachError!RegionInfo { + var info: RegionInfo = .{ + .base_addr = address, + .tag = tag, + .info = undefined, + }; + switch (tag) { + .basic => info.info = .{ .basic = undefined }, + .extended => info.info = .{ .extended = undefined }, + .top => info.info = .{ .top = undefined }, + } var base_len: std.c.mach_vm_size_t = if (len == 1) 2 else len; var objname: std.c.mach_port_t = undefined; - var info: std.c.vm_region_submap_info_64 = undefined; - var count: std.c.mach_msg_type_number_t = std.c.VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + var count: std.c.mach_msg_type_number_t = switch (tag) { + .basic => std.c.VM_REGION_BASIC_INFO_COUNT, + .extended => std.c.VM_REGION_EXTENDED_INFO_COUNT, + .top => std.c.VM_REGION_TOP_INFO_COUNT, + }; switch (std.c.getKernError(std.c.mach_vm_region( task.port, - &base_addr, + &info.base_addr, &base_len, - std.c.VM_REGION_BASIC_INFO_64, - @ptrCast(std.c.vm_region_info_t, &info), + switch (tag) { + .basic => std.c.VM_REGION_BASIC_INFO_64, + .extended => std.c.VM_REGION_EXTENDED_INFO, + .top => std.c.VM_REGION_TOP_INFO, + }, + switch (tag) { + .basic => @ptrCast(std.c.vm_region_info_t, &info.info.basic), + .extended => @ptrCast(std.c.vm_region_info_t, &info.info.extended), + .top => @ptrCast(std.c.vm_region_info_t, &info.info.top), + }, &count, &objname, ))) { - .SUCCESS => return info.protection, + .SUCCESS => return info, .FAILURE => return error.PermissionDenied, else => |err| { log.err("mach_vm_region kernel call failed with error code: {s}", .{@tagName(err)}); @@ -48,6 +89,67 @@ const mach_task = if (builtin.target.isDarwin()) struct { } } + pub const RegionSubmapInfo = struct { + pub const Tag = enum { + short, + full, + }; + + tag: Tag, + base_addr: u64, + info: union { + short: std.c.vm_region_submap_short_info_64, + full: std.c.vm_region_submap_info_64, + }, + }; + + pub fn getRegionSubmapInfo( + task: MachTask, + address: u64, + len: usize, + nesting_depth: u32, + tag: RegionSubmapInfo.Tag, + ) MachError!RegionSubmapInfo { + var info: RegionSubmapInfo = .{ + .base_addr = address, + .tag = tag, + .info = undefined, + }; + switch (tag) { + .short => info.info = .{ .short = undefined }, + .full => info.info = .{ .full = undefined }, + } + var nesting = nesting_depth; + var base_len: std.c.mach_vm_size_t = if (len == 1) 2 else len; + var count: std.c.mach_msg_type_number_t = switch (tag) { + .short => std.c.VM_REGION_SUBMAP_SHORT_INFO_COUNT_64, + .full => std.c.VM_REGION_SUBMAP_INFO_COUNT_64, + }; + switch (std.c.getKernError(std.c.mach_vm_region_recurse( + task.port, + &info.base_addr, + &base_len, + &nesting, + switch (tag) { + .short => @ptrCast(std.c.vm_region_recurse_info_t, &info.info.short), + .full => @ptrCast(std.c.vm_region_recurse_info_t, &info.info.full), + }, + &count, + ))) { + .SUCCESS => return info, + .FAILURE => return error.PermissionDenied, + else => |err| { + log.err("mach_vm_region kernel call failed with error code: {s}", .{@tagName(err)}); + return error.Unexpected; + }, + } + } + + pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!std.c.vm_prot_t { + const info = try task.getRegionSubmapInfo(address, len, 0, .short); + return info.info.short.protection; + } + pub fn setMaxProtection(task: MachTask, address: u64, len: usize, prot: std.c.vm_prot_t) MachError!void { return task.setProtectionImpl(address, len, true, prot); } @@ -216,4 +318,8 @@ const mach_task = if (builtin.target.isDarwin()) struct { } return MachTask{ .port = port }; } + + pub fn machTaskForSelf() MachTask { + return .{ .port = std.c.mach_task_self() }; + } } else struct {};