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_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 {

View File

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