authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-21 18:47:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:12-07:00
log4f4ddf5ef2f2e2ee2774e0a5311b099ea19d9ce2
tree5a57b5870be7d3e1bb9eea8a1350930d525b02ab
parent50a2bb58d23a686f52b389c062f0299cc2a5f8ed

hot code swapping PoC working

- improve fn prototypes of process_vm_writev - make the memory writable in the ELF file - force the linker to always append the function - write updates with process_vm_writev

2 files changed, 48 insertions(+), 13 deletions(-)

lib/std/os/linux.zig+10-10
...@@ -1716,26 +1716,26 @@ pub fn pidfd_send_signal(pidfd: fd_t, sig: i32, info: ?*siginfo_t, flags: u32) u...@@ -1716,26 +1716,26 @@ pub fn pidfd_send_signal(pidfd: fd_t, sig: i32, info: ?*siginfo_t, flags: u32) u
1716 );1716 );
1717}1717}
17181718
1719pub fn process_vm_readv(pid: pid_t, local: [*]const iovec, local_count: usize, remote: [*]const iovec, remote_count: usize, flags: usize) usize {1719pub fn process_vm_readv(pid: pid_t, local: []iovec, remote: []const iovec_const, flags: usize) usize {
1720 return syscall6(1720 return syscall6(
1721 .process_vm_readv,1721 .process_vm_readv,
1722 @bitCast(usize, @as(isize, pid)),1722 @bitCast(usize, @as(isize, pid)),
1723 @ptrToInt(local),1723 @ptrToInt(local.ptr),
1724 local_count,1724 local.len,
1725 @ptrToInt(remote),1725 @ptrToInt(remote.ptr),
1726 remote_count,1726 remote.len,
1727 flags,1727 flags,
1728 );1728 );
1729}1729}
17301730
1731pub fn process_vm_writev(pid: pid_t, local: [*]const iovec, local_count: usize, remote: [*]const iovec, remote_count: usize, flags: usize) usize {1731pub fn process_vm_writev(pid: pid_t, local: []const iovec_const, remote: []const iovec_const, flags: usize) usize {
1732 return syscall6(1732 return syscall6(
1733 .process_vm_writev,1733 .process_vm_writev,
1734 @bitCast(usize, @as(isize, pid)),1734 @bitCast(usize, @as(isize, pid)),
1735 @ptrToInt(local),1735 @ptrToInt(local.ptr),
1736 local_count,1736 local.len,
1737 @ptrToInt(remote),1737 @ptrToInt(remote.ptr),
1738 remote_count,1738 remote.len,
1739 flags,1739 flags,
1740 );1740 );
1741}1741}
src/link/Elf.zig+38-3
...@@ -467,7 +467,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -467,7 +467,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
467 .p_paddr = entry_addr,467 .p_paddr = entry_addr,
468 .p_memsz = file_size,468 .p_memsz = file_size,
469 .p_align = p_align,469 .p_align = p_align,
470 .p_flags = elf.PF_X | elf.PF_R,470 .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
471 });471 });
472 self.entry_addr = null;472 self.entry_addr = null;
473 self.phdr_table_dirty = true;473 self.phdr_table_dirty = true;
...@@ -493,7 +493,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -493,7 +493,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
493 .p_paddr = got_addr,493 .p_paddr = got_addr,
494 .p_memsz = file_size,494 .p_memsz = file_size,
495 .p_align = p_align,495 .p_align = p_align,
496 .p_flags = elf.PF_R,496 .p_flags = elf.PF_R | elf.PF_W,
497 });497 });
498 self.phdr_table_dirty = true;498 self.phdr_table_dirty = true;
499 }499 }
...@@ -516,7 +516,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -516,7 +516,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
516 .p_paddr = rodata_addr,516 .p_paddr = rodata_addr,
517 .p_memsz = file_size,517 .p_memsz = file_size,
518 .p_align = p_align,518 .p_align = p_align,
519 .p_flags = elf.PF_R,519 .p_flags = elf.PF_R | elf.PF_W,
520 });520 });
521 self.phdr_table_dirty = true;521 self.phdr_table_dirty = true;
522 }522 }
...@@ -2451,6 +2451,23 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2451,6 +2451,23 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2451 const phdr_index = self.sections.items(.phdr_index)[shdr_index];2451 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
2452 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;2452 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;
2453 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;2453 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
2454
2455 if (self.base.child_pid) |pid| {
2456 var code_vec: [1]std.os.iovec_const = .{.{
2457 .iov_base = code.ptr,
2458 .iov_len = code.len,
2459 }};
2460 var remote_vec: [1]std.os.iovec_const = .{.{
2461 .iov_base = @intToPtr([*]u8, local_sym.st_value),
2462 .iov_len = code.len,
2463 }};
2464 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
2465 switch (std.os.errno(rc)) {
2466 .SUCCESS => assert(rc == code.len),
2467 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
2468 }
2469 }
2470
2454 try self.base.file.?.pwriteAll(code, file_offset);2471 try self.base.file.?.pwriteAll(code, file_offset);
24552472
2456 return local_sym;2473 return local_sym;
...@@ -2820,6 +2837,8 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {...@@ -2820,6 +2837,8 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2820 const endian = self.base.options.target.cpu.arch.endian();2837 const endian = self.base.options.target.cpu.arch.endian();
2821 const shdr = &self.sections.items(.shdr)[self.got_section_index.?];2838 const shdr = &self.sections.items(.shdr)[self.got_section_index.?];
2822 const off = shdr.sh_offset + @as(u64, entry_size) * index;2839 const off = shdr.sh_offset + @as(u64, entry_size) * index;
2840 const phdr = &self.program_headers.items[self.phdr_got_index.?];
2841 const vaddr = phdr.p_vaddr + @as(u64, entry_size) * index;
2823 switch (entry_size) {2842 switch (entry_size) {
2824 2 => {2843 2 => {
2825 var buf: [2]u8 = undefined;2844 var buf: [2]u8 = undefined;
...@@ -2835,6 +2854,22 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {...@@ -2835,6 +2854,22 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2835 var buf: [8]u8 = undefined;2854 var buf: [8]u8 = undefined;
2836 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);2855 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);
2837 try self.base.file.?.pwriteAll(&buf, off);2856 try self.base.file.?.pwriteAll(&buf, off);
2857
2858 if (self.base.child_pid) |pid| {
2859 var local_vec: [1]std.os.iovec_const = .{.{
2860 .iov_base = &buf,
2861 .iov_len = buf.len,
2862 }};
2863 var remote_vec: [1]std.os.iovec_const = .{.{
2864 .iov_base = @intToPtr([*]u8, vaddr),
2865 .iov_len = buf.len,
2866 }};
2867 const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
2868 switch (std.os.errno(rc)) {
2869 .SUCCESS => assert(rc == buf.len),
2870 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
2871 }
2872 }
2838 },2873 },
2839 else => unreachable,2874 else => unreachable,
2840 }2875 }