Commit 37192bcdcb

Jakub Konka <kubkon@jakubkonka.com>
2023-03-17 09:25:49
macos: HCS PoC working
1 parent f1e25cf
Changed files (4)
lib/std/c/darwin.zig
@@ -3316,7 +3316,7 @@ pub fn getKernError(err: kern_return_t) KernE {
 
 pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
     if (std.os.unexpected_error_tracing) {
-        std.debug.print("unexpected errno: {d}\n", .{@enumToInt(err)});
+        std.debug.print("unexpected error: {d}\n", .{@enumToInt(err)});
         std.debug.dumpCurrentStackTrace(null);
     }
     return error.Unexpected;
src/link/MachO.zig
@@ -587,7 +587,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
     try self.allocateSpecialSymbols();
 
     for (self.relocs.keys()) |atom_index| {
-        if (self.relocs.get(atom_index) == null) continue;
+        const relocs = self.relocs.get(atom_index).?;
+        const needs_update = for (relocs.items) |reloc| {
+            if (reloc.dirty) break true;
+        } else false;
+
+        if (!needs_update) continue;
 
         const atom = self.getAtom(atom_index);
         const sym = atom.getSymbol(self);
@@ -1085,7 +1090,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
             log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid});
             break :blk;
         };
-        self.writeAtomToMemory(task, section.segment_index, sym.n_value, code) catch |err| {
+        self.updateAtomInMemory(task, section.segment_index, sym.n_value, code) catch |err| {
             log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)});
         };
     }
@@ -1093,13 +1098,13 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
     try self.base.file.?.pwriteAll(code, file_offset);
 }
 
-fn writeAtomToMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {
+fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {
     const segment = self.segments.items[segment_index];
-    if (!segment.isWriteable()) {
-        try task.setCurrProtection(addr, code.len, macho.PROT.READ | macho.PROT.WRITE | macho.PROT.COPY);
-    }
-    defer if (!segment.isWriteable()) task.setCurrProtection(addr, code.len, segment.initprot) catch {};
-    const nwritten = try task.writeMem(addr, code, self.base.options.target.cpu.arch);
+    const cpu_arch = self.base.options.target.cpu.arch;
+    const nwritten = if (!segment.isWriteable())
+        try task.writeMemProtected(addr, code, cpu_arch)
+    else
+        try task.writeMem(addr, code, cpu_arch);
     if (nwritten != code.len) return error.InputOutput;
 }
 
@@ -1109,6 +1114,7 @@ fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
 }
 
 fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
+    log.debug("marking relocs dirty by target: {}", .{target});
     // TODO: reverse-lookup might come in handy here
     for (self.relocs.values()) |*relocs| {
         for (relocs.items) |*reloc| {
@@ -1119,6 +1125,7 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
 }
 
 fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
+    log.debug("marking relocs dirty by address: {x}", .{addr});
     for (self.relocs.values()) |*relocs| {
         for (relocs.items) |*reloc| {
             const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;
@@ -1743,6 +1750,8 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {
     if (self.dyld_stub_binder_index != null) return;
     if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports
 
+    log.debug("resolving dyld_stub_binder", .{});
+
     const gpa = self.base.allocator;
     const sym_index = try self.allocateSymbol();
     const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
@@ -2829,6 +2838,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
 
     if (self.linkedit_segment_cmd_index == null) {
         self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
+
         try self.segments.append(gpa, .{
             .segname = makeStaticString("__LINKEDIT"),
             .maxprot = macho.PROT.READ,
src/link.zig
@@ -397,9 +397,10 @@ pub const File = struct {
                             if (macho.mach_task == null) {
                                 if (std.os.darwin.machTaskForPid(pid)) |task| {
                                     macho.mach_task = task;
-                                    std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {
-                                        log.warn("ptrace failure: {s}", .{@errorName(err)});
-                                    };
+                                    // TODO enable ones we register for exceptions
+                                    // std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {
+                                    //     log.warn("ptrace failure: {s}", .{@errorName(err)});
+                                    // };
                                 } else |err| {
                                     log.warn("failed to acquire Mach task for child process: {s}", .{@errorName(err)});
                                 }
@@ -443,9 +444,11 @@ pub const File = struct {
                         .linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
                             log.warn("ptrace failure: {s}", .{@errorName(err)});
                         },
-                        .macos => std.os.ptrace(std.os.darwin.PT.KILL, pid, 0, 0) catch |err| {
-                            log.warn("ptrace failure: {s}", .{@errorName(err)});
-                        },
+                        .macos => {},
+                        // TODO see comment above in makeWritable
+                        // .macos => std.os.ptrace(std.os.darwin.PT.DETACH, pid, 0, 0) catch |err| {
+                        //     log.warn("ptrace failure: {s}", .{@errorName(err)});
+                        // },
                         else => return error.HotSwapUnavailableOnHostOperatingSystem,
                     }
                 }
src/main.zig
@@ -3320,21 +3320,20 @@ fn buildOutputType(
 
             try server.listen(.{ .in = ip4_addr });
 
-            while (true) {
-                const conn = try server.accept();
-                defer conn.stream.close();
-
-                try serve(
-                    comp,
-                    .{ .handle = conn.stream.handle },
-                    .{ .handle = conn.stream.handle },
-                    test_exec_args.items,
-                    self_exe_path,
-                    arg_mode,
-                    all_args,
-                    runtime_args_start,
-                );
-            }
+            const conn = try server.accept();
+            defer conn.stream.close();
+
+            try serve(
+                comp,
+                .{ .handle = conn.stream.handle },
+                .{ .handle = conn.stream.handle },
+                test_exec_args.items,
+                self_exe_path,
+                arg_mode,
+                all_args,
+                runtime_args_start,
+            );
+            return cleanExit();
         },
     }
 
@@ -3465,9 +3464,7 @@ fn serve(
         const hdr = try server.receiveMessage();
 
         switch (hdr.tag) {
-            .exit => {
-                return cleanExit();
-            },
+            .exit => return,
             .update => {
                 assert(main_progress_node.recently_updated_child == null);
                 tracy.frameMark();