macos: update Mach routines for accessing page info

This commit is contained in:
Jakub Konka 2022-03-17 10:41:51 +01:00
parent 3c3826bf93
commit 648afbc839
2 changed files with 201 additions and 16 deletions

View File

@ -155,6 +155,7 @@ pub const vm_map_t = mach_port_t;
pub const vm_map_read_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_flavor_t = c_int;
pub const vm_region_info_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 mach_vm_address_t = usize;
pub const vm_offset_t = usize; pub const vm_offset_t = usize;
pub const mach_vm_size_t = u64; 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, info_cnt: *mach_msg_type_number_t,
object_name: *mach_port_t, object_name: *mach_port_t,
) kern_return_t; ) kern_return_t;
pub extern "c" fn mach_vm_region_recurse(
pub const VM_REGION_BASIC_INFO_64 = 9; target_task: vm_map_t,
pub const VM_REGION_SUBMAP_SHORT_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_info_64) / @sizeOf(natural_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 vm_inherit_t = u32;
pub const memory_object_offset_t = u64; pub const memory_object_offset_t = u64;
pub const vm_behavior_t = i32; 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_SHARE: vm_inherit_t = 0;
pub const VM_INHERIT_COPY: vm_inherit_t = 1; 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_CAN_REUSE: vm_behavior_t = 10;
pub const VM_BEHAVIOR_PAGEOUT: vm_behavior_t = 11; pub const VM_BEHAVIOR_PAGEOUT: vm_behavior_t = 11;
pub const vm32_object_id_t = u32; pub const VM_REGION_BASIC_INFO_64 = 9;
pub const vm_object_id_t = u64; 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 { pub const vm_region_submap_info_64 = extern struct {
// present across protection // present across protection
@ -262,6 +309,34 @@ pub const vm_region_submap_info_64 = extern struct {
object_id_full: vm_object_id_t, 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_act_t = mach_port_t;
pub const thread_state_t = *natural_t; pub const thread_state_t = *natural_t;
pub const mach_port_array_t = *mach_port_t; pub const mach_port_array_t = *mach_port_t;
@ -986,9 +1061,13 @@ pub const MAP = struct {
}; };
pub const MSF = struct { pub const MSF = struct {
pub const ASYNC = 1; pub const ASYNC = 0x1;
pub const INVALIDATE = 2; pub const INVALIDATE = 0x2;
pub const SYNC = 4; // invalidate, leave mapped
pub const KILLPAGES = 0x4;
// deactivate, leave mapped
pub const DEACTIVATE = 0x8;
pub const SYNC = 0x10;
}; };
pub const SA = struct { pub const SA = struct {

View File

@ -24,22 +24,63 @@ const mach_task = if (builtin.target.isDarwin()) struct {
return self.port != 0; return self.port != 0;
} }
pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!std.c.vm_prot_t { pub const RegionInfo = struct {
var base_addr = address; 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 base_len: std.c.mach_vm_size_t = if (len == 1) 2 else len;
var objname: std.c.mach_port_t = undefined; 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 = switch (tag) {
var count: std.c.mach_msg_type_number_t = std.c.VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; .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( switch (std.c.getKernError(std.c.mach_vm_region(
task.port, task.port,
&base_addr, &info.base_addr,
&base_len, &base_len,
std.c.VM_REGION_BASIC_INFO_64, switch (tag) {
@ptrCast(std.c.vm_region_info_t, &info), .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, &count,
&objname, &objname,
))) { ))) {
.SUCCESS => return info.protection, .SUCCESS => return info,
.FAILURE => return error.PermissionDenied, .FAILURE => return error.PermissionDenied,
else => |err| { else => |err| {
log.err("mach_vm_region kernel call failed with error code: {s}", .{@tagName(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 { pub fn setMaxProtection(task: MachTask, address: u64, len: usize, prot: std.c.vm_prot_t) MachError!void {
return task.setProtectionImpl(address, len, true, prot); return task.setProtectionImpl(address, len, true, prot);
} }
@ -216,4 +318,8 @@ const mach_task = if (builtin.target.isDarwin()) struct {
} }
return MachTask{ .port = port }; return MachTask{ .port = port };
} }
pub fn machTaskForSelf() MachTask {
return .{ .port = std.c.mach_task_self() };
}
} else struct {}; } else struct {};