Commit 76bceb240d
Changed files (5)
lib
src
link
lib/std/os/darwin.zig
@@ -1,214 +1,219 @@
const std = @import("std");
-const c = std.c.darwin;
+const builtin = @import("builtin");
const log = std.log;
const mem = std.mem;
-pub const MachError = error{
- /// Not enough permissions held to perform the requested kernel
- /// call.
- PermissionDenied,
- /// Kernel returned an unhandled and unexpected error code.
- /// This is a catch-all for any yet unobserved kernel response
- /// to some Mach message.
- Unexpected,
-};
-
-pub const MachTask = struct {
- port: c.mach_port_name_t,
-
- pub fn isValid(self: MachTask) bool {
- return self.port != 0;
- }
-
- pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!c.vm_prot_t {
- var base_addr = address;
- var base_len: c.mach_vm_size_t = if (len == 1) 2 else len;
- var objname: c.mach_port_t = undefined;
- var info: c.vm_region_submap_info_64 = undefined;
- var count: c.mach_msg_type_number_t = c.VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
- switch (c.getKernError(c.mach_vm_region(
- task.port,
- &base_addr,
- &base_len,
- c.VM_REGION_BASIC_INFO_64,
- @ptrCast(c.vm_region_info_t, &info),
- &count,
- &objname,
- ))) {
- .SUCCESS => return info.protection,
- .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 setMaxProtection(task: MachTask, address: u64, len: usize, prot: c.vm_prot_t) MachError!void {
- return task.setProtectionImpl(address, len, true, prot);
- }
-
- pub fn setCurrProtection(task: MachTask, address: u64, len: usize, prot: c.vm_prot_t) MachError!void {
- return task.setProtectionImpl(address, len, false, prot);
- }
-
- fn setProtectionImpl(task: MachTask, address: u64, len: usize, set_max: bool, prot: c.vm_prot_t) MachError!void {
- switch (c.getKernError(c.mach_vm_protect(task.port, address, len, @boolToInt(set_max), prot))) {
- .SUCCESS => return,
- .FAILURE => return error.PermissionDenied,
- else => |err| {
- log.err("mach_vm_protect kernel call failed with error code: {s}", .{@tagName(err)});
- return error.Unexpected;
- },
- }
- }
-
- /// Will write to VM even if current protection attributes specifically prohibit
- /// us from doing so, by temporarily setting protection level to a level with VM_PROT_COPY
- /// variant, and resetting after a successful or unsuccessful write.
- pub fn writeMemProtected(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize {
- const curr_prot = try task.getCurrProtection(address, buf.len);
- try task.setCurrProtection(
- address,
- buf.len,
- c.PROT.READ | c.PROT.WRITE | c.PROT.COPY,
- );
- defer {
- task.setCurrProtection(address, buf.len, curr_prot) catch {};
+pub usingnamespace std.c;
+pub usingnamespace mach_task;
+
+const mach_task = if (builtin.target.isDarwin()) struct {
+ pub const MachError = error{
+ /// Not enough permissions held to perform the requested kernel
+ /// call.
+ PermissionDenied,
+ /// Kernel returned an unhandled and unexpected error code.
+ /// This is a catch-all for any yet unobserved kernel response
+ /// to some Mach message.
+ Unexpected,
+ };
+
+ pub const MachTask = struct {
+ port: std.c.mach_port_name_t,
+
+ pub fn isValid(self: MachTask) bool {
+ return self.port != 0;
}
- return task.writeMem(address, buf, arch);
- }
- pub fn writeMem(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize {
- const count = buf.len;
- var total_written: usize = 0;
- var curr_addr = address;
- const page_size = try getPageSize(task); // TODO we probably can assume value here
- var out_buf = buf[0..];
-
- while (total_written < count) {
- const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_written);
- switch (c.getKernError(c.mach_vm_write(
+ pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!std.c.vm_prot_t {
+ var base_addr = address;
+ 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;
+ switch (std.c.getKernError(std.c.mach_vm_region(
task.port,
- curr_addr,
- @ptrToInt(out_buf.ptr),
- @intCast(c.mach_msg_type_number_t, curr_size),
+ &base_addr,
+ &base_len,
+ std.c.VM_REGION_BASIC_INFO_64,
+ @ptrCast(std.c.vm_region_info_t, &info),
+ &count,
+ &objname,
))) {
- .SUCCESS => {},
+ .SUCCESS => return info.protection,
.FAILURE => return error.PermissionDenied,
else => |err| {
- log.err("mach_vm_write kernel call failed with error code: {s}", .{@tagName(err)});
+ log.err("mach_vm_region kernel call failed with error code: {s}", .{@tagName(err)});
return error.Unexpected;
},
}
+ }
- switch (arch) {
- .aarch64 => {
- var mattr_value: c.vm_machine_attribute_val_t = c.MATTR_VAL_CACHE_FLUSH;
- switch (c.getKernError(c.vm_machine_attribute(
- task.port,
- curr_addr,
- curr_size,
- c.MATTR_CACHE,
- &mattr_value,
- ))) {
- .SUCCESS => {},
- .FAILURE => return error.PermissionDenied,
- else => |err| {
- log.err("vm_machine_attribute kernel call failed with error code: {s}", .{@tagName(err)});
- return error.Unexpected;
- },
- }
- },
- .x86_64 => {},
- else => unreachable,
- }
-
- out_buf = out_buf[curr_size..];
- total_written += curr_size;
- curr_addr += curr_size;
+ 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 total_written;
- }
+ pub fn setCurrProtection(task: MachTask, address: u64, len: usize, prot: std.c.vm_prot_t) MachError!void {
+ return task.setProtectionImpl(address, len, false, prot);
+ }
- pub fn readMem(task: MachTask, address: u64, buf: []u8) MachError!usize {
- const count = buf.len;
- var total_read: usize = 0;
- var curr_addr = address;
- const page_size = try getPageSize(task); // TODO we probably can assume value here
- var out_buf = buf[0..];
-
- while (total_read < count) {
- const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_read);
- var curr_bytes_read: c.mach_msg_type_number_t = 0;
- var vm_memory: c.vm_offset_t = undefined;
- switch (c.getKernError(c.mach_vm_read(task.port, curr_addr, curr_size, &vm_memory, &curr_bytes_read))) {
- .SUCCESS => {},
+ fn setProtectionImpl(task: MachTask, address: u64, len: usize, set_max: bool, prot: std.c.vm_prot_t) MachError!void {
+ switch (std.c.getKernError(std.c.mach_vm_protect(task.port, address, len, @boolToInt(set_max), prot))) {
+ .SUCCESS => return,
.FAILURE => return error.PermissionDenied,
else => |err| {
- log.err("mach_vm_read kernel call failed with error code: {s}", .{@tagName(err)});
+ log.err("mach_vm_protect kernel call failed with error code: {s}", .{@tagName(err)});
return error.Unexpected;
},
}
+ }
+
+ /// Will write to VM even if current protection attributes specifically prohibit
+ /// us from doing so, by temporarily setting protection level to a level with VM_PROT_COPY
+ /// variant, and resetting after a successful or unsuccessful write.
+ pub fn writeMemProtected(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize {
+ const curr_prot = try task.getCurrProtection(address, buf.len);
+ try task.setCurrProtection(
+ address,
+ buf.len,
+ std.c.PROT.READ | std.c.PROT.WRITE | std.c.PROT.COPY,
+ );
+ defer {
+ task.setCurrProtection(address, buf.len, curr_prot) catch {};
+ }
+ return task.writeMem(address, buf, arch);
+ }
- @memcpy(out_buf[0..].ptr, @intToPtr([*]const u8, vm_memory), curr_bytes_read);
- _ = c.vm_deallocate(c.mach_task_self(), vm_memory, curr_bytes_read);
+ pub fn writeMem(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize {
+ const count = buf.len;
+ var total_written: usize = 0;
+ var curr_addr = address;
+ const page_size = try getPageSize(task); // TODO we probably can assume value here
+ var out_buf = buf[0..];
+
+ while (total_written < count) {
+ const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_written);
+ switch (std.c.getKernError(std.c.mach_vm_write(
+ task.port,
+ curr_addr,
+ @ptrToInt(out_buf.ptr),
+ @intCast(std.c.mach_msg_type_number_t, curr_size),
+ ))) {
+ .SUCCESS => {},
+ .FAILURE => return error.PermissionDenied,
+ else => |err| {
+ log.err("mach_vm_write kernel call failed with error code: {s}", .{@tagName(err)});
+ return error.Unexpected;
+ },
+ }
+
+ switch (arch) {
+ .aarch64 => {
+ var mattr_value: std.c.vm_machine_attribute_val_t = std.c.MATTR_VAL_CACHE_FLUSH;
+ switch (std.c.getKernError(std.c.vm_machine_attribute(
+ task.port,
+ curr_addr,
+ curr_size,
+ std.c.MATTR_CACHE,
+ &mattr_value,
+ ))) {
+ .SUCCESS => {},
+ .FAILURE => return error.PermissionDenied,
+ else => |err| {
+ log.err("vm_machine_attribute kernel call failed with error code: {s}", .{@tagName(err)});
+ return error.Unexpected;
+ },
+ }
+ },
+ .x86_64 => {},
+ else => unreachable,
+ }
+
+ out_buf = out_buf[curr_size..];
+ total_written += curr_size;
+ curr_addr += curr_size;
+ }
- out_buf = out_buf[curr_bytes_read..];
- curr_addr += curr_bytes_read;
- total_read += curr_bytes_read;
+ return total_written;
}
- return total_read;
- }
+ pub fn readMem(task: MachTask, address: u64, buf: []u8) MachError!usize {
+ const count = buf.len;
+ var total_read: usize = 0;
+ var curr_addr = address;
+ const page_size = try getPageSize(task); // TODO we probably can assume value here
+ var out_buf = buf[0..];
+
+ while (total_read < count) {
+ const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_read);
+ var curr_bytes_read: std.c.mach_msg_type_number_t = 0;
+ var vm_memory: std.c.vm_offset_t = undefined;
+ switch (std.c.getKernError(std.c.mach_vm_read(task.port, curr_addr, curr_size, &vm_memory, &curr_bytes_read))) {
+ .SUCCESS => {},
+ .FAILURE => return error.PermissionDenied,
+ else => |err| {
+ log.err("mach_vm_read kernel call failed with error code: {s}", .{@tagName(err)});
+ return error.Unexpected;
+ },
+ }
+
+ @memcpy(out_buf[0..].ptr, @intToPtr([*]const u8, vm_memory), curr_bytes_read);
+ _ = std.c.vm_deallocate(std.c.mach_task_self(), vm_memory, curr_bytes_read);
+
+ out_buf = out_buf[curr_bytes_read..];
+ curr_addr += curr_bytes_read;
+ total_read += curr_bytes_read;
+ }
- fn maxBytesLeftInPage(page_size: usize, address: u64, count: usize) usize {
- var left = count;
- if (page_size > 0) {
- const page_offset = address % page_size;
- const bytes_left_in_page = page_size - page_offset;
- if (count > bytes_left_in_page) {
- left = bytes_left_in_page;
+ return total_read;
+ }
+
+ fn maxBytesLeftInPage(page_size: usize, address: u64, count: usize) usize {
+ var left = count;
+ if (page_size > 0) {
+ const page_offset = address % page_size;
+ const bytes_left_in_page = page_size - page_offset;
+ if (count > bytes_left_in_page) {
+ left = bytes_left_in_page;
+ }
}
+ return left;
}
- return left;
- }
- fn getPageSize(task: MachTask) MachError!usize {
- if (task.isValid()) {
- var info_count = c.TASK_VM_INFO_COUNT;
- var vm_info: c.task_vm_info_data_t = undefined;
- switch (c.getKernError(c.task_info(
- task.port,
- c.TASK_VM_INFO,
- @ptrCast(c.task_info_t, &vm_info),
- &info_count,
- ))) {
- .SUCCESS => return @intCast(usize, vm_info.page_size),
- else => {},
+ fn getPageSize(task: MachTask) MachError!usize {
+ if (task.isValid()) {
+ var info_count = std.c.TASK_VM_INFO_COUNT;
+ var vm_info: std.c.task_vm_info_data_t = undefined;
+ switch (std.c.getKernError(std.c.task_info(
+ task.port,
+ std.c.TASK_VM_INFO,
+ @ptrCast(std.c.task_info_t, &vm_info),
+ &info_count,
+ ))) {
+ .SUCCESS => return @intCast(usize, vm_info.page_size),
+ else => {},
+ }
+ }
+ var page_size: std.c.vm_size_t = undefined;
+ switch (std.c.getKernError(std.c._host_page_size(std.c.mach_host_self(), &page_size))) {
+ .SUCCESS => return page_size,
+ else => |err| {
+ log.err("_host_page_size kernel call failed with error code: {s}", .{@tagName(err)});
+ return error.Unexpected;
+ },
}
}
- var page_size: c.vm_size_t = undefined;
- switch (c.getKernError(c._host_page_size(c.mach_host_self(), &page_size))) {
- .SUCCESS => return page_size,
+ };
+
+ pub fn machTaskForPid(pid: std.os.pid_t) MachError!MachTask {
+ var port: std.c.mach_port_name_t = undefined;
+ switch (std.c.getKernError(std.c.task_for_pid(std.c.mach_task_self(), pid, &port))) {
+ .SUCCESS => {},
+ .FAILURE => return error.PermissionDenied,
else => |err| {
- log.err("_host_page_size kernel call failed with error code: {s}", .{@tagName(err)});
+ log.err("task_for_pid kernel call failed with error code: {s}", .{@tagName(err)});
return error.Unexpected;
},
}
+ return MachTask{ .port = port };
}
-};
-
-pub fn machTaskForPid(pid: c.pid_t) MachError!MachTask {
- var port: c.mach_port_name_t = undefined;
- switch (c.getKernError(c.task_for_pid(c.mach_task_self(), pid, &port))) {
- .SUCCESS => {},
- .FAILURE => return error.PermissionDenied,
- else => |err| {
- log.err("task_for_pid kernel call failed with error code: {s}", .{@tagName(err)});
- return error.Unexpected;
- },
- }
- return MachTask{ .port = port };
-}
+} else struct {};
lib/std/c.zig
@@ -39,12 +39,10 @@ pub fn versionCheck(glibc_version: std.builtin.Version) type {
};
}
-pub const darwin = @import("c/darwin.zig");
-
pub usingnamespace switch (builtin.os.tag) {
.linux => @import("c/linux.zig"),
.windows => @import("c/windows.zig"),
- .macos, .ios, .tvos, .watchos => darwin,
+ .macos, .ios, .tvos, .watchos => @import("c/darwin.zig"),
.freebsd, .kfreebsd => @import("c/freebsd.zig"),
.netbsd => @import("c/netbsd.zig"),
.dragonfly => @import("c/dragonfly.zig"),
lib/std/macho.zig
@@ -2,15 +2,15 @@ const std = @import("std");
const builtin = @import("builtin");
const assert = std.debug.assert;
const io = std.io;
-const c = std.c.darwin;
const mem = std.mem;
const meta = std.meta;
const testing = std.testing;
const Allocator = mem.Allocator;
-pub const cpu_type_t = c.integer_t;
-pub const cpu_subtype_t = c.integer_t;
+pub const cpu_type_t = c_int;
+pub const cpu_subtype_t = c_int;
+pub const vm_prot_t = c_int;
pub const mach_header = extern struct {
magic: u32,
@@ -605,10 +605,10 @@ pub const segment_command = extern struct {
filesize: u32,
/// maximum VM protection
- maxprot: c.vm_prot_t,
+ maxprot: vm_prot_t,
/// initial VM protection
- initprot: c.vm_prot_t,
+ initprot: vm_prot_t,
/// number of sections in segment
nsects: u32,
@@ -642,10 +642,10 @@ pub const segment_command_64 = extern struct {
filesize: u64 = 0,
/// maximum VM protection
- maxprot: c.vm_prot_t = c.PROT.NONE,
+ maxprot: vm_prot_t = PROT.NONE,
/// initial VM protection
- initprot: c.vm_prot_t = c.PROT.NONE,
+ initprot: vm_prot_t = PROT.NONE,
/// number of sections in segment
nsects: u32 = 0,
@@ -656,6 +656,23 @@ pub const segment_command_64 = extern struct {
}
};
+pub const PROT = struct {
+ /// [MC2] no permissions
+ pub const NONE: vm_prot_t = 0x00;
+ /// [MC2] pages can be read
+ pub const READ: vm_prot_t = 0x01;
+ /// [MC2] pages can be written
+ pub const WRITE: vm_prot_t = 0x02;
+ /// [MC2] pages can be executed
+ pub const EXEC: vm_prot_t = 0x04;
+ /// When a caller finds that they cannot obtain write permission on a
+ /// mapped entry, the following flag can be used. The entry will be
+ /// made "needs copy" effectively copying the object (using COW),
+ /// and write permission will be added to the maximum protections for
+ /// the associated entry.
+ pub const COPY: vm_prot_t = 0x10;
+};
+
/// A segment is made up of zero or more sections. Non-MH_OBJECT files have
/// all of their segments with the proper sections in each, and padded to the
/// specified segment alignment when produced by the link editor. The first
@@ -2148,8 +2165,8 @@ test "read-write segment command" {
.vmaddr = 4294967296,
.vmsize = 294912,
.filesize = 294912,
- .maxprot = c.PROT.READ | c.PROT.WRITE | c.PROT.EXEC,
- .initprot = c.PROT.EXEC | c.PROT.READ,
+ .maxprot = PROT.READ | PROT.WRITE | PROT.EXEC,
+ .initprot = PROT.EXEC | PROT.READ,
.nsects = 1,
},
};
lib/std/os.zig
@@ -29,11 +29,7 @@ const Allocator = std.mem.Allocator;
const Preopen = std.fs.wasi.Preopen;
const PreopenList = std.fs.wasi.PreopenList;
-pub const darwin = struct {
- pub usingnamespace std.c;
- pub usingnamespace @import("os/darwin.zig");
-};
-
+pub const darwin = @import("os/darwin.zig");
pub const dragonfly = std.c;
pub const freebsd = std.c;
pub const haiku = std.c;
@@ -51,6 +47,7 @@ comptime {
}
test {
+ _ = darwin;
_ = linux;
_ = uefi;
_ = wasi;
src/link/MachO.zig
@@ -4,7 +4,6 @@ const std = @import("std");
const build_options = @import("build_options");
const builtin = @import("builtin");
const assert = std.debug.assert;
-const darwin = std.os.darwin;
const fmt = std.fmt;
const fs = std.fs;
const log = std.log.scoped(.link);
@@ -4344,8 +4343,8 @@ fn populateMissingMetadata(self: *MachO) !void {
.vmaddr = pagezero_vmsize,
.vmsize = needed_size,
.filesize = needed_size,
- .maxprot = darwin.PROT.READ | darwin.PROT.EXEC,
- .initprot = darwin.PROT.READ | darwin.PROT.EXEC,
+ .maxprot = macho.PROT.READ | macho.PROT.EXEC,
+ .initprot = macho.PROT.READ | macho.PROT.EXEC,
},
},
});
@@ -4449,8 +4448,8 @@ fn populateMissingMetadata(self: *MachO) !void {
.vmsize = needed_size,
.fileoff = fileoff,
.filesize = needed_size,
- .maxprot = darwin.PROT.READ | darwin.PROT.WRITE,
- .initprot = darwin.PROT.READ | darwin.PROT.WRITE,
+ .maxprot = macho.PROT.READ | macho.PROT.WRITE,
+ .initprot = macho.PROT.READ | macho.PROT.WRITE,
},
},
});
@@ -4498,8 +4497,8 @@ fn populateMissingMetadata(self: *MachO) !void {
.vmsize = needed_size,
.fileoff = fileoff,
.filesize = needed_size,
- .maxprot = darwin.PROT.READ | darwin.PROT.WRITE,
- .initprot = darwin.PROT.READ | darwin.PROT.WRITE,
+ .maxprot = macho.PROT.READ | macho.PROT.WRITE,
+ .initprot = macho.PROT.READ | macho.PROT.WRITE,
},
},
});
@@ -4607,8 +4606,8 @@ fn populateMissingMetadata(self: *MachO) !void {
.segname = makeStaticString("__LINKEDIT"),
.vmaddr = vmaddr,
.fileoff = fileoff,
- .maxprot = darwin.PROT.READ,
- .initprot = darwin.PROT.READ,
+ .maxprot = macho.PROT.READ,
+ .initprot = macho.PROT.READ,
},
},
});