summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/platform/kvm/testutil
diff options
context:
space:
mode:
authorGoogler <noreply@google.com>2018-04-27 10:37:02 -0700
committerAdin Scannell <ascannell@google.com>2018-04-28 01:44:26 -0400
commitd02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 (patch)
tree54f95eef73aee6bacbfc736fffc631be2605ed53 /pkg/sentry/platform/kvm/testutil
parentf70210e742919f40aa2f0934a22f1c9ba6dada62 (diff)
Check in gVisor.
PiperOrigin-RevId: 194583126 Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463
Diffstat (limited to 'pkg/sentry/platform/kvm/testutil')
-rw-r--r--pkg/sentry/platform/kvm/testutil/BUILD15
-rw-r--r--pkg/sentry/platform/kvm/testutil/testutil.go75
-rw-r--r--pkg/sentry/platform/kvm/testutil/testutil_amd64.go135
-rw-r--r--pkg/sentry/platform/kvm/testutil/testutil_amd64.s98
4 files changed, 323 insertions, 0 deletions
diff --git a/pkg/sentry/platform/kvm/testutil/BUILD b/pkg/sentry/platform/kvm/testutil/BUILD
new file mode 100644
index 000000000..8533a8d89
--- /dev/null
+++ b/pkg/sentry/platform/kvm/testutil/BUILD
@@ -0,0 +1,15 @@
+package(licenses = ["notice"]) # Apache 2.0
+
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "testutil",
+ testonly = 1,
+ srcs = [
+ "testutil.go",
+ "testutil_amd64.go",
+ "testutil_amd64.s",
+ ],
+ importpath = "gvisor.googlesource.com/gvisor/pkg/sentry/platform/kvm/testutil",
+ visibility = ["//pkg/sentry/platform/kvm:__pkg__"],
+)
diff --git a/pkg/sentry/platform/kvm/testutil/testutil.go b/pkg/sentry/platform/kvm/testutil/testutil.go
new file mode 100644
index 000000000..8a614e25d
--- /dev/null
+++ b/pkg/sentry/platform/kvm/testutil/testutil.go
@@ -0,0 +1,75 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package testutil provides common assembly stubs for testing.
+package testutil
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Getpid executes a trivial system call.
+func Getpid()
+
+// Touch touches the value in the first register.
+func Touch()
+
+// SyscallLoop executes a syscall and loops.
+func SyscallLoop()
+
+// SpinLoop spins on the CPU.
+func SpinLoop()
+
+// HaltLoop immediately halts and loops.
+func HaltLoop()
+
+// TwiddleRegsFault twiddles registers then faults.
+func TwiddleRegsFault()
+
+// TwiddleRegsSyscall twiddles registers then executes a syscall.
+func TwiddleRegsSyscall()
+
+// TwiddleSegments reads segments into known registers.
+func TwiddleSegments()
+
+// FloatingPointWorks is a floating point test.
+//
+// It returns true or false.
+func FloatingPointWorks() bool
+
+// RegisterMismatchError is used for checking registers.
+type RegisterMismatchError []string
+
+// Error returns a human-readable error.
+func (r RegisterMismatchError) Error() string {
+ return strings.Join([]string(r), ";")
+}
+
+// addRegisterMisatch allows simple chaining of register mismatches.
+func addRegisterMismatch(err error, reg string, got, expected interface{}) error {
+ errStr := fmt.Sprintf("%s got %08x, expected %08x", reg, got, expected)
+ switch r := err.(type) {
+ case nil:
+ // Return a new register mismatch.
+ return RegisterMismatchError{errStr}
+ case RegisterMismatchError:
+ // Append the error.
+ r = append(r, errStr)
+ return r
+ default:
+ // Leave as is.
+ return err
+ }
+}
diff --git a/pkg/sentry/platform/kvm/testutil/testutil_amd64.go b/pkg/sentry/platform/kvm/testutil/testutil_amd64.go
new file mode 100644
index 000000000..39286a0af
--- /dev/null
+++ b/pkg/sentry/platform/kvm/testutil/testutil_amd64.go
@@ -0,0 +1,135 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build amd64
+
+package testutil
+
+import (
+ "reflect"
+ "syscall"
+)
+
+// SetTestTarget sets the rip appropriately.
+func SetTestTarget(regs *syscall.PtraceRegs, fn func()) {
+ regs.Rip = uint64(reflect.ValueOf(fn).Pointer())
+}
+
+// SetTouchTarget sets rax appropriately.
+func SetTouchTarget(regs *syscall.PtraceRegs, target *uintptr) {
+ if target != nil {
+ regs.Rax = uint64(reflect.ValueOf(target).Pointer())
+ } else {
+ regs.Rax = 0
+ }
+}
+
+// RewindSyscall rewinds a syscall RIP.
+func RewindSyscall(regs *syscall.PtraceRegs) {
+ regs.Rip -= 2
+}
+
+// SetTestRegs initializes registers to known values.
+func SetTestRegs(regs *syscall.PtraceRegs) {
+ regs.R15 = 0x15
+ regs.R14 = 0x14
+ regs.R13 = 0x13
+ regs.R12 = 0x12
+ regs.Rbp = 0xb9
+ regs.Rbx = 0xb4
+ regs.R11 = 0x11
+ regs.R10 = 0x10
+ regs.R9 = 0x09
+ regs.R8 = 0x08
+ regs.Rax = 0x44
+ regs.Rcx = 0xc4
+ regs.Rdx = 0xd4
+ regs.Rsi = 0x51
+ regs.Rdi = 0xd1
+ regs.Rsp = 0x59
+}
+
+// CheckTestRegs checks that registers were twiddled per TwiddleRegs.
+func CheckTestRegs(regs *syscall.PtraceRegs, full bool) (err error) {
+ if need := ^uint64(0x15); regs.R15 != need {
+ err = addRegisterMismatch(err, "R15", regs.R15, need)
+ }
+ if need := ^uint64(0x14); regs.R14 != need {
+ err = addRegisterMismatch(err, "R14", regs.R14, need)
+ }
+ if need := ^uint64(0x13); regs.R13 != need {
+ err = addRegisterMismatch(err, "R13", regs.R13, need)
+ }
+ if need := ^uint64(0x12); regs.R12 != need {
+ err = addRegisterMismatch(err, "R12", regs.R12, need)
+ }
+ if need := ^uint64(0xb9); regs.Rbp != need {
+ err = addRegisterMismatch(err, "Rbp", regs.Rbp, need)
+ }
+ if need := ^uint64(0xb4); regs.Rbx != need {
+ err = addRegisterMismatch(err, "Rbx", regs.Rbx, need)
+ }
+ if need := ^uint64(0x10); regs.R10 != need {
+ err = addRegisterMismatch(err, "R10", regs.R10, need)
+ }
+ if need := ^uint64(0x09); regs.R9 != need {
+ err = addRegisterMismatch(err, "R9", regs.R9, need)
+ }
+ if need := ^uint64(0x08); regs.R8 != need {
+ err = addRegisterMismatch(err, "R8", regs.R8, need)
+ }
+ if need := ^uint64(0x44); regs.Rax != need {
+ err = addRegisterMismatch(err, "Rax", regs.Rax, need)
+ }
+ if need := ^uint64(0xd4); regs.Rdx != need {
+ err = addRegisterMismatch(err, "Rdx", regs.Rdx, need)
+ }
+ if need := ^uint64(0x51); regs.Rsi != need {
+ err = addRegisterMismatch(err, "Rsi", regs.Rsi, need)
+ }
+ if need := ^uint64(0xd1); regs.Rdi != need {
+ err = addRegisterMismatch(err, "Rdi", regs.Rdi, need)
+ }
+ if need := ^uint64(0x59); regs.Rsp != need {
+ err = addRegisterMismatch(err, "Rsp", regs.Rsp, need)
+ }
+ // Rcx & R11 are ignored if !full is set.
+ if need := ^uint64(0x11); full && regs.R11 != need {
+ err = addRegisterMismatch(err, "R11", regs.R11, need)
+ }
+ if need := ^uint64(0xc4); full && regs.Rcx != need {
+ err = addRegisterMismatch(err, "Rcx", regs.Rcx, need)
+ }
+ return
+}
+
+var fsData uint64 = 0x55
+var gsData uint64 = 0x85
+
+// SetTestSegments initializes segments to known values.
+func SetTestSegments(regs *syscall.PtraceRegs) {
+ regs.Fs_base = uint64(reflect.ValueOf(&fsData).Pointer())
+ regs.Gs_base = uint64(reflect.ValueOf(&gsData).Pointer())
+}
+
+// CheckTestSegments checks that registers were twiddled per TwiddleSegments.
+func CheckTestSegments(regs *syscall.PtraceRegs) (err error) {
+ if regs.Rax != fsData {
+ err = addRegisterMismatch(err, "Rax", regs.Rax, fsData)
+ }
+ if regs.Rbx != gsData {
+ err = addRegisterMismatch(err, "Rbx", regs.Rcx, gsData)
+ }
+ return
+}
diff --git a/pkg/sentry/platform/kvm/testutil/testutil_amd64.s b/pkg/sentry/platform/kvm/testutil/testutil_amd64.s
new file mode 100644
index 000000000..3b5ad8817
--- /dev/null
+++ b/pkg/sentry/platform/kvm/testutil/testutil_amd64.s
@@ -0,0 +1,98 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build amd64
+
+// test_util_amd64.s provides AMD64 test functions.
+
+#include "funcdata.h"
+#include "textflag.h"
+
+TEXT ·Getpid(SB),NOSPLIT,$0
+ NO_LOCAL_POINTERS
+ MOVQ $39, AX // getpid
+ SYSCALL
+ RET
+
+TEXT ·Touch(SB),NOSPLIT,$0
+start:
+ MOVQ 0(AX), BX // deref AX
+ MOVQ $39, AX // getpid
+ SYSCALL
+ JMP start
+
+TEXT ·HaltLoop(SB),NOSPLIT,$0
+start:
+ HLT
+ JMP start
+
+TEXT ·SyscallLoop(SB),NOSPLIT,$0
+start:
+ SYSCALL
+ JMP start
+
+TEXT ·SpinLoop(SB),NOSPLIT,$0
+start:
+ JMP start
+
+TEXT ·FloatingPointWorks(SB),NOSPLIT,$0-8
+ NO_LOCAL_POINTERS
+ MOVQ $1, AX
+ MOVQ AX, X0
+ MOVQ $39, AX // getpid
+ SYSCALL
+ MOVQ X0, AX
+ CMPQ AX, $1
+ SETEQ ret+0(FP)
+ RET
+
+#define TWIDDLE_REGS() \
+ NOTQ R15; \
+ NOTQ R14; \
+ NOTQ R13; \
+ NOTQ R12; \
+ NOTQ BP; \
+ NOTQ BX; \
+ NOTQ R11; \
+ NOTQ R10; \
+ NOTQ R9; \
+ NOTQ R8; \
+ NOTQ AX; \
+ NOTQ CX; \
+ NOTQ DX; \
+ NOTQ SI; \
+ NOTQ DI; \
+ NOTQ SP;
+
+TEXT ·TwiddleRegsSyscall(SB),NOSPLIT,$0
+ TWIDDLE_REGS()
+ SYSCALL
+ RET // never reached
+
+TEXT ·TwiddleRegsFault(SB),NOSPLIT,$0
+ TWIDDLE_REGS()
+ JMP AX // must fault
+ RET // never reached
+
+#define READ_FS() BYTE $0x64; BYTE $0x48; BYTE $0x8b; BYTE $0x00;
+#define READ_GS() BYTE $0x65; BYTE $0x48; BYTE $0x8b; BYTE $0x00;
+
+TEXT ·TwiddleSegments(SB),NOSPLIT,$0
+ MOVQ $0x0, AX
+ READ_GS()
+ MOVQ AX, BX
+ MOVQ $0x0, AX
+ READ_FS()
+ SYSCALL
+ RET // never reached