authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-17 09:25:49+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-18 21:53:36+01:00
log37192bcdcb38be2266133f6d46dce5a842984c06
treef529668b8c48d0c2b6d123bccfc0bf8556c218a1
parentf1e25cf43ec60075a4fc6f3eceb5a3af1f9f0712

macos: HCS PoC working


4 files changed, 43 insertions(+), 33 deletions(-)

lib/std/c/darwin.zig+1-1
...@@ -3316,7 +3316,7 @@ pub fn getKernError(err: kern_return_t) KernE {...@@ -3316,7 +3316,7 @@ pub fn getKernError(err: kern_return_t) KernE {
33163316
3317pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {3317pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
3318 if (std.os.unexpected_error_tracing) {3318 if (std.os.unexpected_error_tracing) {
3319 std.debug.print("unexpected errno: {d}\n", .{@enumToInt(err)});3319 std.debug.print("unexpected error: {d}\n", .{@enumToInt(err)});
3320 std.debug.dumpCurrentStackTrace(null);3320 std.debug.dumpCurrentStackTrace(null);
3321 }3321 }
3322 return error.Unexpected;3322 return error.Unexpected;
src/link.zig+9-6
...@@ -397,9 +397,10 @@ pub const File = struct {...@@ -397,9 +397,10 @@ pub const File = struct {
397 if (macho.mach_task == null) {397 if (macho.mach_task == null) {
398 if (std.os.darwin.machTaskForPid(pid)) |task| {398 if (std.os.darwin.machTaskForPid(pid)) |task| {
399 macho.mach_task = task;399 macho.mach_task = task;
400 std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {400 // TODO enable ones we register for exceptions
401 log.warn("ptrace failure: {s}", .{@errorName(err)});401 // std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {
402 };402 // log.warn("ptrace failure: {s}", .{@errorName(err)});
403 // };
403 } else |err| {404 } else |err| {
404 log.warn("failed to acquire Mach task for child process: {s}", .{@errorName(err)});405 log.warn("failed to acquire Mach task for child process: {s}", .{@errorName(err)});
405 }406 }
...@@ -443,9 +444,11 @@ pub const File = struct {...@@ -443,9 +444,11 @@ pub const File = struct {
443 .linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {444 .linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
444 log.warn("ptrace failure: {s}", .{@errorName(err)});445 log.warn("ptrace failure: {s}", .{@errorName(err)});
445 },446 },
446 .macos => std.os.ptrace(std.os.darwin.PT.KILL, pid, 0, 0) catch |err| {447 .macos => {},
447 log.warn("ptrace failure: {s}", .{@errorName(err)});448 // TODO see comment above in makeWritable
448 },449 // .macos => std.os.ptrace(std.os.darwin.PT.DETACH, pid, 0, 0) catch |err| {
450 // log.warn("ptrace failure: {s}", .{@errorName(err)});
451 // },
449 else => return error.HotSwapUnavailableOnHostOperatingSystem,452 else => return error.HotSwapUnavailableOnHostOperatingSystem,
450 }453 }
451 }454 }
src/link/MachO.zig+18-8
...@@ -587,7 +587,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -587,7 +587,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
587 try self.allocateSpecialSymbols();587 try self.allocateSpecialSymbols();
588588
589 for (self.relocs.keys()) |atom_index| {589 for (self.relocs.keys()) |atom_index| {
590 if (self.relocs.get(atom_index) == null) continue;590 const relocs = self.relocs.get(atom_index).?;
591 const needs_update = for (relocs.items) |reloc| {
592 if (reloc.dirty) break true;
593 } else false;
594
595 if (!needs_update) continue;
591596
592 const atom = self.getAtom(atom_index);597 const atom = self.getAtom(atom_index);
593 const sym = atom.getSymbol(self);598 const sym = atom.getSymbol(self);
...@@ -1085,7 +1090,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {...@@ -1085,7 +1090,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
1085 log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid});1090 log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid});
1086 break :blk;1091 break :blk;
1087 };1092 };
1088 self.writeAtomToMemory(task, section.segment_index, sym.n_value, code) catch |err| {1093 self.updateAtomInMemory(task, section.segment_index, sym.n_value, code) catch |err| {
1089 log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)});1094 log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)});
1090 };1095 };
1091 }1096 }
...@@ -1093,13 +1098,13 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {...@@ -1093,13 +1098,13 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
1093 try self.base.file.?.pwriteAll(code, file_offset);1098 try self.base.file.?.pwriteAll(code, file_offset);
1094}1099}
10951100
1096fn writeAtomToMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {1101fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {
1097 const segment = self.segments.items[segment_index];1102 const segment = self.segments.items[segment_index];
1098 if (!segment.isWriteable()) {1103 const cpu_arch = self.base.options.target.cpu.arch;
1099 try task.setCurrProtection(addr, code.len, macho.PROT.READ | macho.PROT.WRITE | macho.PROT.COPY);1104 const nwritten = if (!segment.isWriteable())
1100 }1105 try task.writeMemProtected(addr, code, cpu_arch)
1101 defer if (!segment.isWriteable()) task.setCurrProtection(addr, code.len, segment.initprot) catch {};1106 else
1102 const nwritten = try task.writeMem(addr, code, self.base.options.target.cpu.arch);1107 try task.writeMem(addr, code, cpu_arch);
1103 if (nwritten != code.len) return error.InputOutput;1108 if (nwritten != code.len) return error.InputOutput;
1104}1109}
11051110
...@@ -1109,6 +1114,7 @@ fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {...@@ -1109,6 +1114,7 @@ fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
1109}1114}
11101115
1111fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {1116fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
1117 log.debug("marking relocs dirty by target: {}", .{target});
1112 // TODO: reverse-lookup might come in handy here1118 // TODO: reverse-lookup might come in handy here
1113 for (self.relocs.values()) |*relocs| {1119 for (self.relocs.values()) |*relocs| {
1114 for (relocs.items) |*reloc| {1120 for (relocs.items) |*reloc| {
...@@ -1119,6 +1125,7 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {...@@ -1119,6 +1125,7 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
1119}1125}
11201126
1121fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {1127fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
1128 log.debug("marking relocs dirty by address: {x}", .{addr});
1122 for (self.relocs.values()) |*relocs| {1129 for (self.relocs.values()) |*relocs| {
1123 for (relocs.items) |*reloc| {1130 for (relocs.items) |*reloc| {
1124 const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;1131 const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;
...@@ -1743,6 +1750,8 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {...@@ -1743,6 +1750,8 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {
1743 if (self.dyld_stub_binder_index != null) return;1750 if (self.dyld_stub_binder_index != null) return;
1744 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports1751 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports
17451752
1753 log.debug("resolving dyld_stub_binder", .{});
1754
1746 const gpa = self.base.allocator;1755 const gpa = self.base.allocator;
1747 const sym_index = try self.allocateSymbol();1756 const sym_index = try self.allocateSymbol();
1748 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };1757 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
...@@ -2829,6 +2838,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -2829,6 +2838,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
28292838
2830 if (self.linkedit_segment_cmd_index == null) {2839 if (self.linkedit_segment_cmd_index == null) {
2831 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);2840 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
2841
2832 try self.segments.append(gpa, .{2842 try self.segments.append(gpa, .{
2833 .segname = makeStaticString("__LINKEDIT"),2843 .segname = makeStaticString("__LINKEDIT"),
2834 .maxprot = macho.PROT.READ,2844 .maxprot = macho.PROT.READ,
src/main.zig+15-18
...@@ -3320,21 +3320,20 @@ fn buildOutputType(...@@ -3320,21 +3320,20 @@ fn buildOutputType(
33203320
3321 try server.listen(.{ .in = ip4_addr });3321 try server.listen(.{ .in = ip4_addr });
33223322
3323 while (true) {3323 const conn = try server.accept();
3324 const conn = try server.accept();3324 defer conn.stream.close();
3325 defer conn.stream.close();3325
33263326 try serve(
3327 try serve(3327 comp,
3328 comp,3328 .{ .handle = conn.stream.handle },
3329 .{ .handle = conn.stream.handle },3329 .{ .handle = conn.stream.handle },
3330 .{ .handle = conn.stream.handle },3330 test_exec_args.items,
3331 test_exec_args.items,3331 self_exe_path,
3332 self_exe_path,3332 arg_mode,
3333 arg_mode,3333 all_args,
3334 all_args,3334 runtime_args_start,
3335 runtime_args_start,3335 );
3336 );3336 return cleanExit();
3337 }
3338 },3337 },
3339 }3338 }
33403339
...@@ -3465,9 +3464,7 @@ fn serve(...@@ -3465,9 +3464,7 @@ fn serve(
3465 const hdr = try server.receiveMessage();3464 const hdr = try server.receiveMessage();
34663465
3467 switch (hdr.tag) {3466 switch (hdr.tag) {
3468 .exit => {3467 .exit => return,
3469 return cleanExit();
3470 },
3471 .update => {3468 .update => {
3472 assert(main_progress_node.recently_updated_child == null);3469 assert(main_progress_node.recently_updated_child == null);
3473 tracy.frameMark();3470 tracy.frameMark();