mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Enable syscall ptrace test on arm64.
Signed-off-by: Haibo Xu <haibo.xu@arm.com> Change-Id: I5bb8fa7d580d173b1438d6465e1adb442216c8fa
This commit is contained in:
@@ -88,6 +88,9 @@ type Context interface {
|
||||
// SyscallNo returns the syscall number.
|
||||
SyscallNo() uintptr
|
||||
|
||||
// SyscallSaveOrig save orignal register value.
|
||||
SyscallSaveOrig()
|
||||
|
||||
// SyscallArgs returns the syscall arguments in an array.
|
||||
SyscallArgs() SyscallArguments
|
||||
|
||||
|
||||
@@ -18,6 +18,13 @@ package arch
|
||||
|
||||
const restartSyscallNr = uintptr(219)
|
||||
|
||||
// SyscallSaveOrig save the value of the register which is clobbered in
|
||||
// syscall handler(doSyscall()).
|
||||
//
|
||||
// Noop on x86.
|
||||
func (c *context64) SyscallSaveOrig() {
|
||||
}
|
||||
|
||||
// SyscallNo returns the syscall number according to the 64-bit convention.
|
||||
func (c *context64) SyscallNo() uintptr {
|
||||
return uintptr(c.Regs.Orig_rax)
|
||||
|
||||
@@ -18,6 +18,17 @@ package arch
|
||||
|
||||
const restartSyscallNr = uintptr(128)
|
||||
|
||||
// SyscallSaveOrig save the value of the register R0 which is clobbered in
|
||||
// syscall handler(doSyscall()).
|
||||
//
|
||||
// In linux, at the entry of the syscall handler(el0_svc_common()), value of R0
|
||||
// is saved to the pt_regs.orig_x0 in kernel code. But currently, the orig_x0
|
||||
// was not accessible to the user space application, so we have to do the same
|
||||
// operation in the sentry code to save the R0 value into the App context.
|
||||
func (c *context64) SyscallSaveOrig() {
|
||||
c.OrigR0 = c.Regs.Regs[0]
|
||||
}
|
||||
|
||||
// SyscallNo returns the syscall number according to the 64-bit convention.
|
||||
func (c *context64) SyscallNo() uintptr {
|
||||
return uintptr(c.Regs.Regs[8])
|
||||
@@ -40,7 +51,7 @@ func (c *context64) SyscallNo() uintptr {
|
||||
// R30: the link register.
|
||||
func (c *context64) SyscallArgs() SyscallArguments {
|
||||
return SyscallArguments{
|
||||
SyscallArgument{Value: uintptr(c.Regs.Regs[0])},
|
||||
SyscallArgument{Value: uintptr(c.OrigR0)},
|
||||
SyscallArgument{Value: uintptr(c.Regs.Regs[1])},
|
||||
SyscallArgument{Value: uintptr(c.Regs.Regs[2])},
|
||||
SyscallArgument{Value: uintptr(c.Regs.Regs[3])},
|
||||
|
||||
@@ -194,6 +194,19 @@ func (t *Task) executeSyscall(sysno uintptr, args arch.SyscallArguments) (rval u
|
||||
//
|
||||
// The syscall path is very hot; avoid defer.
|
||||
func (t *Task) doSyscall() taskRunState {
|
||||
// Save value of the register which is clobbered in the following
|
||||
// t.Arch().SetReturn(-ENOSYS) operation. This is dedicated to arm64.
|
||||
//
|
||||
// On x86, register rax was shared by syscall number and return
|
||||
// value, and at the entry of the syscall handler, the rax was
|
||||
// saved to regs.orig_rax which was exposed to user space.
|
||||
// But on arm64, syscall number was passed through X8, and the X0
|
||||
// was shared by the first syscall argument and return value. The
|
||||
// X0 was saved to regs.orig_x0 which was not exposed to user space.
|
||||
// So we have to do the same operation here to save the X0 value
|
||||
// into the task context.
|
||||
t.Arch().SyscallSaveOrig()
|
||||
|
||||
sysno := t.Arch().SyscallNo()
|
||||
args := t.Arch().SyscallArgs()
|
||||
|
||||
@@ -269,6 +282,7 @@ func (*runSyscallAfterSyscallEnterStop) execute(t *Task) taskRunState {
|
||||
return (*runSyscallExit)(nil)
|
||||
}
|
||||
args := t.Arch().SyscallArgs()
|
||||
|
||||
return t.doSyscallInvoke(sysno, args)
|
||||
}
|
||||
|
||||
|
||||
@@ -400,9 +400,11 @@ TEST(PtraceTest, GetRegSet) {
|
||||
// Read exactly the full register set.
|
||||
EXPECT_EQ(iov.iov_len, sizeof(regs));
|
||||
|
||||
#ifdef __x86_64__
|
||||
#if defined(__x86_64__)
|
||||
// Child called kill(2), with SIGSTOP as arg 2.
|
||||
EXPECT_EQ(regs.rsi, SIGSTOP);
|
||||
#elif defined(__aarch64__)
|
||||
EXPECT_EQ(regs.regs[1], SIGSTOP);
|
||||
#endif
|
||||
|
||||
// Suppress SIGSTOP and resume the child.
|
||||
@@ -752,15 +754,23 @@ TEST(PtraceTest,
|
||||
SyscallSucceeds());
|
||||
EXPECT_TRUE(siginfo.si_code == SIGTRAP || siginfo.si_code == (SIGTRAP | 0x80))
|
||||
<< "si_code = " << siginfo.si_code;
|
||||
#ifdef __x86_64__
|
||||
|
||||
{
|
||||
struct user_regs_struct regs = {};
|
||||
ASSERT_THAT(ptrace(PTRACE_GETREGS, child_pid, 0, ®s), SyscallSucceeds());
|
||||
struct iovec iov;
|
||||
iov.iov_base = ®s;
|
||||
iov.iov_len = sizeof(regs);
|
||||
EXPECT_THAT(ptrace(PTRACE_GETREGSET, child_pid, NT_PRSTATUS, &iov),
|
||||
SyscallSucceeds());
|
||||
#if defined(__x86_64__)
|
||||
EXPECT_TRUE(regs.orig_rax == SYS_vfork || regs.orig_rax == SYS_clone)
|
||||
<< "orig_rax = " << regs.orig_rax;
|
||||
EXPECT_EQ(grandchild_pid, regs.rax);
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
EXPECT_TRUE(regs.regs[8] == SYS_clone) << "regs[8] = " << regs.regs[8];
|
||||
EXPECT_EQ(grandchild_pid, regs.regs[0]);
|
||||
#endif // defined(__x86_64__)
|
||||
}
|
||||
|
||||
// After this point, the child will be making wait4 syscalls that will be
|
||||
// interrupted by saving, so saving is not permitted. Note that this is
|
||||
@@ -805,14 +815,21 @@ TEST(PtraceTest,
|
||||
SyscallSucceedsWithValue(child_pid));
|
||||
EXPECT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80))
|
||||
<< " status " << status;
|
||||
#ifdef __x86_64__
|
||||
{
|
||||
struct user_regs_struct regs = {};
|
||||
ASSERT_THAT(ptrace(PTRACE_GETREGS, child_pid, 0, ®s), SyscallSucceeds());
|
||||
struct iovec iov;
|
||||
iov.iov_base = ®s;
|
||||
iov.iov_len = sizeof(regs);
|
||||
EXPECT_THAT(ptrace(PTRACE_GETREGSET, child_pid, NT_PRSTATUS, &iov),
|
||||
SyscallSucceeds());
|
||||
#if defined(__x86_64__)
|
||||
EXPECT_EQ(SYS_wait4, regs.orig_rax);
|
||||
EXPECT_EQ(grandchild_pid, regs.rax);
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
EXPECT_EQ(SYS_wait4, regs.regs[8]);
|
||||
EXPECT_EQ(grandchild_pid, regs.regs[0]);
|
||||
#endif // defined(__x86_64__)
|
||||
}
|
||||
|
||||
// Detach from the child and wait for it to exit.
|
||||
ASSERT_THAT(ptrace(PTRACE_DETACH, child_pid, 0, 0), SyscallSucceeds());
|
||||
|
||||
Reference in New Issue
Block a user