clone tests to help debugging
This commit is contained in:
13
src/main.zig
13
src/main.zig
@@ -326,6 +326,19 @@ test "nolibc_pie_readlink" {
|
|||||||
// try testReadlink("libc_pie_readlink");
|
// try testReadlink("libc_pie_readlink");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
test "nolibc_nopie_clone_raw" {
|
||||||
|
try testHelper(
|
||||||
|
&.{ flicker_path, getTestExePath("nolibc_nopie_clone_raw") },
|
||||||
|
"Child: Hello\nParent: Goodbye\n",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
test "nolibc_pie_clone_raw" {
|
||||||
|
try testHelper(
|
||||||
|
&.{ flicker_path, getTestExePath("nolibc_pie_clone_raw") },
|
||||||
|
"Child: Hello\nParent: Goodbye\n",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test "echo" {
|
test "echo" {
|
||||||
try testHelper(&.{ "echo", "Hello", "There" }, "Hello There\n");
|
try testHelper(&.{ "echo", "Hello", "There" }, "Hello There\n");
|
||||||
}
|
}
|
||||||
|
|||||||
65
src/test/clone_raw.zig
Normal file
65
src/test/clone_raw.zig
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const linux = std.os.linux;
|
||||||
|
const clone = linux.CLONE;
|
||||||
|
|
||||||
|
var child_stack: [4096 * 4]u8 align(16) = undefined;
|
||||||
|
pub fn main() !void {
|
||||||
|
// SIGCHLD: Send signal to parent on exit (required for waitpid)
|
||||||
|
const flags = clone.VM | clone.FILES | clone.FS | clone.SIGHAND | linux.SIG.CHLD;
|
||||||
|
|
||||||
|
// Stack grows downwards. Point to the end.
|
||||||
|
const stack_top = @intFromPtr(&child_stack) + child_stack.len;
|
||||||
|
|
||||||
|
const msg = "Child: Hello\n";
|
||||||
|
const msg_len = msg.len;
|
||||||
|
|
||||||
|
// We use inline assembly to perform the clone syscall and handle the child path completely to
|
||||||
|
// avoid the compiler generating code that relies on the parent's stack frame in the child
|
||||||
|
// process (where the stack is empty).
|
||||||
|
const ret = asm volatile (
|
||||||
|
\\ syscall
|
||||||
|
\\ test %%rax, %%rax
|
||||||
|
\\ jnz 1f
|
||||||
|
\\
|
||||||
|
\\ # Child Path
|
||||||
|
\\ # Write to stdout
|
||||||
|
\\ mov $1, %%rdi # fd = 1 (stdout)
|
||||||
|
\\ mov %[msg], %%rsi # buffer
|
||||||
|
\\ mov %[len], %%rdx # length
|
||||||
|
\\ mov $1, %%rax # SYS_write
|
||||||
|
\\ syscall
|
||||||
|
\\
|
||||||
|
\\ # Exit
|
||||||
|
\\ mov $0, %%rdi # code = 0
|
||||||
|
\\ mov $60, %%rax # SYS_exit
|
||||||
|
\\ syscall
|
||||||
|
\\
|
||||||
|
\\ # Should not be reached
|
||||||
|
\\ ud2
|
||||||
|
\\
|
||||||
|
\\ 1:
|
||||||
|
\\ # Parent Path continues
|
||||||
|
: [ret] "={rax}" (-> usize),
|
||||||
|
: [number] "{rax}" (@intFromEnum(linux.syscalls.X64.clone)),
|
||||||
|
[arg1] "{rdi}" (flags),
|
||||||
|
[arg2] "{rsi}" (stack_top),
|
||||||
|
[arg3] "{rdx}" (0),
|
||||||
|
[arg4] "{r10}" (0),
|
||||||
|
[arg5] "{r8}" (0),
|
||||||
|
[msg] "r" (msg.ptr),
|
||||||
|
[len] "r" (msg_len),
|
||||||
|
: .{ .rcx = true, .r11 = true, .memory = true });
|
||||||
|
|
||||||
|
// Parent Process
|
||||||
|
const child_pid: i32 = @intCast(ret);
|
||||||
|
if (child_pid < 0) {
|
||||||
|
_ = linux.syscall3(.write, 1, @intFromPtr("Parent: Clone failed\n"), 21);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status: u32 = 0;
|
||||||
|
// wait4 for the child to exit
|
||||||
|
_ = linux.syscall4(.wait4, @as(usize, @intCast(child_pid)), @intFromPtr(&status), 0, 0);
|
||||||
|
|
||||||
|
_ = linux.syscall3(.write, 1, @intFromPtr("Parent: Goodbye\n"), 16);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user