summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rwxr-xr-xpkg/abi/linux/file_amd64.go2
-rwxr-xr-xpkg/abi/linux/file_arm64.go2
-rwxr-xr-xpkg/abi/linux/linux_abi_autogen_unsafe.go193
-rwxr-xr-xpkg/abi/linux/linux_amd64_abi_autogen_unsafe.go182
-rwxr-xr-xpkg/abi/linux/linux_arm64_abi_autogen_unsafe.go186
-rw-r--r--pkg/abi/linux/time.go2
-rwxr-xr-xpkg/sentry/syscalls/linux/linux_amd64_state_autogen.go1
-rwxr-xr-xpkg/sentry/syscalls/linux/linux_arm64_state_autogen.go1
-rw-r--r--pkg/sentry/syscalls/linux/sys_stat.go26
-rwxr-xr-xpkg/sentry/syscalls/linux/sys_stat_amd64.go75
-rwxr-xr-xpkg/sentry/syscalls/linux/sys_stat_arm64.go77
-rwxr-xr-xtools/go_marshal/marshal/marshal.go94
-rwxr-xr-xtools/go_marshal/marshal/marshal_state_autogen.go3
13 files changed, 688 insertions, 156 deletions
diff --git a/pkg/abi/linux/file_amd64.go b/pkg/abi/linux/file_amd64.go
index 8693d49c8..6b72364ea 100755
--- a/pkg/abi/linux/file_amd64.go
+++ b/pkg/abi/linux/file_amd64.go
@@ -25,6 +25,8 @@ const (
)
// Stat represents struct stat.
+//
+// +marshal
type Stat struct {
Dev uint64
Ino uint64
diff --git a/pkg/abi/linux/file_arm64.go b/pkg/abi/linux/file_arm64.go
index ea3adc5f5..6492c9038 100755
--- a/pkg/abi/linux/file_arm64.go
+++ b/pkg/abi/linux/file_arm64.go
@@ -25,6 +25,8 @@ const (
)
// Stat represents struct stat.
+//
+// +marshal
type Stat struct {
Dev uint64
Ino uint64
diff --git a/pkg/abi/linux/linux_abi_autogen_unsafe.go b/pkg/abi/linux/linux_abi_autogen_unsafe.go
new file mode 100755
index 000000000..d8d4cb088
--- /dev/null
+++ b/pkg/abi/linux/linux_abi_autogen_unsafe.go
@@ -0,0 +1,193 @@
+// Automatically generated marshal implementation. See tools/go_marshal.
+
+package linux
+
+import (
+ "gvisor.dev/gvisor/pkg/safecopy"
+ "gvisor.dev/gvisor/pkg/usermem"
+ "gvisor.dev/gvisor/tools/go_marshal/marshal"
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+// Marshallable types used by this file.
+var _ marshal.Marshallable = (*RSeqCriticalSection)(nil)
+var _ marshal.Marshallable = (*Timespec)(nil)
+
+// SizeBytes implements marshal.Marshallable.SizeBytes.
+func (r *RSeqCriticalSection) SizeBytes() int {
+ return 32
+}
+
+// MarshalBytes implements marshal.Marshallable.MarshalBytes.
+func (r *RSeqCriticalSection) MarshalBytes(dst []byte) {
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(r.Version))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(r.Flags))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(r.Start))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(r.PostCommitOffset))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(r.Abort))
+ dst = dst[8:]
+}
+
+// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
+func (r *RSeqCriticalSection) UnmarshalBytes(src []byte) {
+ r.Version = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ r.Flags = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ r.Start = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ r.PostCommitOffset = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ r.Abort = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+}
+
+// Packed implements marshal.Marshallable.Packed.
+func (r *RSeqCriticalSection) Packed() bool {
+ return true
+}
+
+// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
+func (r *RSeqCriticalSection) MarshalUnsafe(dst []byte) {
+ safecopy.CopyIn(dst, unsafe.Pointer(r))
+}
+
+// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
+func (r *RSeqCriticalSection) UnmarshalUnsafe(src []byte) {
+ safecopy.CopyOut(unsafe.Pointer(r), src)
+}
+
+// CopyOut implements marshal.Marshallable.CopyOut.
+func (r *RSeqCriticalSection) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) {
+ // Bypass escape analysis on r. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on r.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(r)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by r's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = r.SizeBytes()
+ hdr.Cap = r.SizeBytes()
+
+ len, err := task.CopyOutBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that r
+ // must live until after the CopyOutBytes.
+ runtime.KeepAlive(r)
+ return len, err
+}
+
+// CopyIn implements marshal.Marshallable.CopyIn.
+func (r *RSeqCriticalSection) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
+ // Bypass escape analysis on r. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on r.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(r)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by r's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = r.SizeBytes()
+ hdr.Cap = r.SizeBytes()
+
+ len, err := task.CopyInBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that r
+ // must live until after the CopyInBytes.
+ runtime.KeepAlive(r)
+ return len, err
+}
+
+// SizeBytes implements marshal.Marshallable.SizeBytes.
+func (t *Timespec) SizeBytes() int {
+ return 16
+}
+
+// MarshalBytes implements marshal.Marshallable.MarshalBytes.
+func (t *Timespec) MarshalBytes(dst []byte) {
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(t.Sec))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(t.Nsec))
+ dst = dst[8:]
+}
+
+// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
+func (t *Timespec) UnmarshalBytes(src []byte) {
+ t.Sec = int64(usermem.ByteOrder.Uint64(src[:8]))
+ src = src[8:]
+ t.Nsec = int64(usermem.ByteOrder.Uint64(src[:8]))
+ src = src[8:]
+}
+
+// Packed implements marshal.Marshallable.Packed.
+func (t *Timespec) Packed() bool {
+ return true
+}
+
+// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
+func (t *Timespec) MarshalUnsafe(dst []byte) {
+ safecopy.CopyIn(dst, unsafe.Pointer(t))
+}
+
+// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
+func (t *Timespec) UnmarshalUnsafe(src []byte) {
+ safecopy.CopyOut(unsafe.Pointer(t), src)
+}
+
+// CopyOut implements marshal.Marshallable.CopyOut.
+func (t *Timespec) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) {
+ // Bypass escape analysis on t. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on t.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(t)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by t's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = t.SizeBytes()
+ hdr.Cap = t.SizeBytes()
+
+ len, err := task.CopyOutBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that t
+ // must live until after the CopyOutBytes.
+ runtime.KeepAlive(t)
+ return len, err
+}
+
+// CopyIn implements marshal.Marshallable.CopyIn.
+func (t *Timespec) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
+ // Bypass escape analysis on t. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on t.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(t)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by t's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = t.SizeBytes()
+ hdr.Cap = t.SizeBytes()
+
+ len, err := task.CopyInBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that t
+ // must live until after the CopyInBytes.
+ runtime.KeepAlive(t)
+ return len, err
+}
+
diff --git a/pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go b/pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go
new file mode 100755
index 000000000..c8162472d
--- /dev/null
+++ b/pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go
@@ -0,0 +1,182 @@
+// Automatically generated marshal implementation. See tools/go_marshal.
+
+// +build amd64
+
+package linux
+
+import (
+ "gvisor.dev/gvisor/pkg/safecopy"
+ "gvisor.dev/gvisor/pkg/usermem"
+ "gvisor.dev/gvisor/tools/go_marshal/marshal"
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+// Marshallable types used by this file.
+var _ marshal.Marshallable = (*Stat)(nil)
+var _ marshal.Marshallable = (*Timespec)(nil)
+
+// SizeBytes implements marshal.Marshallable.SizeBytes.
+func (s *Stat) SizeBytes() int {
+ return 96 +
+ s.ATime.SizeBytes() +
+ s.MTime.SizeBytes() +
+ s.CTime.SizeBytes()
+}
+
+// MarshalBytes implements marshal.Marshallable.MarshalBytes.
+func (s *Stat) MarshalBytes(dst []byte) {
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Dev))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Ino))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Nlink))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.Mode))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.UID))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.GID))
+ dst = dst[4:]
+ // Padding: dst[:sizeof(int32)] ~= int32(0)
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Rdev))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Size))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Blksize))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Blocks))
+ dst = dst[8:]
+ s.ATime.MarshalBytes(dst[:s.ATime.SizeBytes()])
+ dst = dst[s.ATime.SizeBytes():]
+ s.MTime.MarshalBytes(dst[:s.MTime.SizeBytes()])
+ dst = dst[s.MTime.SizeBytes():]
+ s.CTime.MarshalBytes(dst[:s.CTime.SizeBytes()])
+ dst = dst[s.CTime.SizeBytes():]
+ // Padding: dst[:sizeof(int64)*3] ~= [3]int64{0}
+ dst = dst[24:]
+}
+
+// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
+func (s *Stat) UnmarshalBytes(src []byte) {
+ s.Dev = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ s.Ino = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ s.Nlink = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ s.Mode = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ s.UID = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ s.GID = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ // Padding: var _ int32 ~= src[:sizeof(int32)]
+ src = src[4:]
+ s.Rdev = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ s.Size = int64(usermem.ByteOrder.Uint64(src[:8]))
+ src = src[8:]
+ s.Blksize = int64(usermem.ByteOrder.Uint64(src[:8]))
+ src = src[8:]
+ s.Blocks = int64(usermem.ByteOrder.Uint64(src[:8]))
+ src = src[8:]
+ s.ATime.UnmarshalBytes(src[:s.ATime.SizeBytes()])
+ src = src[s.ATime.SizeBytes():]
+ s.MTime.UnmarshalBytes(src[:s.MTime.SizeBytes()])
+ src = src[s.MTime.SizeBytes():]
+ s.CTime.UnmarshalBytes(src[:s.CTime.SizeBytes()])
+ src = src[s.CTime.SizeBytes():]
+ // Padding: ~ copy([3]int64(s._), src[:sizeof(int64)*3])
+ src = src[24:]
+}
+
+// Packed implements marshal.Marshallable.Packed.
+func (s *Stat) Packed() bool {
+ return s.CTime.Packed() && s.ATime.Packed() && s.MTime.Packed()
+}
+
+// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
+func (s *Stat) MarshalUnsafe(dst []byte) {
+ if s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
+ safecopy.CopyIn(dst, unsafe.Pointer(s))
+ } else {
+ s.MarshalBytes(dst)
+ }
+}
+
+// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
+func (s *Stat) UnmarshalUnsafe(src []byte) {
+ if s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
+ safecopy.CopyOut(unsafe.Pointer(s), src)
+ } else {
+ s.UnmarshalBytes(src)
+ }
+}
+
+// CopyOut implements marshal.Marshallable.CopyOut.
+func (s *Stat) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) {
+ if !s.CTime.Packed() && s.ATime.Packed() && s.MTime.Packed() {
+ // Type Stat doesn't have a packed layout in memory, fall back to MarshalBytes.
+ buf := task.CopyScratchBuffer(s.SizeBytes())
+ s.MarshalBytes(buf)
+ return task.CopyOutBytes(addr, buf)
+ }
+
+ // Bypass escape analysis on s. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on s.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(s)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by s's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = s.SizeBytes()
+ hdr.Cap = s.SizeBytes()
+
+ len, err := task.CopyOutBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that s
+ // must live until after the CopyOutBytes.
+ runtime.KeepAlive(s)
+ return len, err
+}
+
+// CopyIn implements marshal.Marshallable.CopyIn.
+func (s *Stat) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
+ if !s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
+ // Type Stat doesn't have a packed layout in memory, fall back to UnmarshalBytes.
+ buf := task.CopyScratchBuffer(s.SizeBytes())
+ n, err := task.CopyInBytes(addr, buf)
+ if err != nil {
+ return n, err
+ }
+ s.UnmarshalBytes(buf)
+ return n, nil
+ }
+
+ // Bypass escape analysis on s. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on s.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(s)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by s's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = s.SizeBytes()
+ hdr.Cap = s.SizeBytes()
+
+ len, err := task.CopyInBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that s
+ // must live until after the CopyInBytes.
+ runtime.KeepAlive(s)
+ return len, err
+}
+
diff --git a/pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go b/pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go
new file mode 100755
index 000000000..118b19ac0
--- /dev/null
+++ b/pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go
@@ -0,0 +1,186 @@
+// Automatically generated marshal implementation. See tools/go_marshal.
+
+// +build arm64
+
+package linux
+
+import (
+ "gvisor.dev/gvisor/pkg/safecopy"
+ "gvisor.dev/gvisor/pkg/usermem"
+ "gvisor.dev/gvisor/tools/go_marshal/marshal"
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+// Marshallable types used by this file.
+var _ marshal.Marshallable = (*Stat)(nil)
+var _ marshal.Marshallable = (*Timespec)(nil)
+
+// SizeBytes implements marshal.Marshallable.SizeBytes.
+func (s *Stat) SizeBytes() int {
+ return 80 +
+ s.ATime.SizeBytes() +
+ s.MTime.SizeBytes() +
+ s.CTime.SizeBytes()
+}
+
+// MarshalBytes implements marshal.Marshallable.MarshalBytes.
+func (s *Stat) MarshalBytes(dst []byte) {
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Dev))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Ino))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.Mode))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.Nlink))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.UID))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.GID))
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Rdev))
+ dst = dst[8:]
+ // Padding: dst[:sizeof(uint64)] ~= uint64(0)
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Size))
+ dst = dst[8:]
+ usermem.ByteOrder.PutUint32(dst[:4], uint32(s.Blksize))
+ dst = dst[4:]
+ // Padding: dst[:sizeof(int32)] ~= int32(0)
+ dst = dst[4:]
+ usermem.ByteOrder.PutUint64(dst[:8], uint64(s.Blocks))
+ dst = dst[8:]
+ s.ATime.MarshalBytes(dst[:s.ATime.SizeBytes()])
+ dst = dst[s.ATime.SizeBytes():]
+ s.MTime.MarshalBytes(dst[:s.MTime.SizeBytes()])
+ dst = dst[s.MTime.SizeBytes():]
+ s.CTime.MarshalBytes(dst[:s.CTime.SizeBytes()])
+ dst = dst[s.CTime.SizeBytes():]
+ // Padding: dst[:sizeof(int32)*2] ~= [2]int32{0}
+ dst = dst[8:]
+}
+
+// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
+func (s *Stat) UnmarshalBytes(src []byte) {
+ s.Dev = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ s.Ino = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ s.Mode = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ s.Nlink = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ s.UID = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ s.GID = usermem.ByteOrder.Uint32(src[:4])
+ src = src[4:]
+ s.Rdev = usermem.ByteOrder.Uint64(src[:8])
+ src = src[8:]
+ // Padding: var _ uint64 ~= src[:sizeof(uint64)]
+ src = src[8:]
+ s.Size = int64(usermem.ByteOrder.Uint64(src[:8]))
+ src = src[8:]
+ s.Blksize = int32(usermem.ByteOrder.Uint32(src[:4]))
+ src = src[4:]
+ // Padding: var _ int32 ~= src[:sizeof(int32)]
+ src = src[4:]
+ s.Blocks = int64(usermem.ByteOrder.Uint64(src[:8]))
+ src = src[8:]
+ s.ATime.UnmarshalBytes(src[:s.ATime.SizeBytes()])
+ src = src[s.ATime.SizeBytes():]
+ s.MTime.UnmarshalBytes(src[:s.MTime.SizeBytes()])
+ src = src[s.MTime.SizeBytes():]
+ s.CTime.UnmarshalBytes(src[:s.CTime.SizeBytes()])
+ src = src[s.CTime.SizeBytes():]
+ // Padding: ~ copy([2]int32(s._), src[:sizeof(int32)*2])
+ src = src[8:]
+}
+
+// Packed implements marshal.Marshallable.Packed.
+func (s *Stat) Packed() bool {
+ return s.CTime.Packed() && s.ATime.Packed() && s.MTime.Packed()
+}
+
+// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
+func (s *Stat) MarshalUnsafe(dst []byte) {
+ if s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
+ safecopy.CopyIn(dst, unsafe.Pointer(s))
+ } else {
+ s.MarshalBytes(dst)
+ }
+}
+
+// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
+func (s *Stat) UnmarshalUnsafe(src []byte) {
+ if s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
+ safecopy.CopyOut(unsafe.Pointer(s), src)
+ } else {
+ s.UnmarshalBytes(src)
+ }
+}
+
+// CopyOut implements marshal.Marshallable.CopyOut.
+func (s *Stat) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) {
+ if !s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
+ // Type Stat doesn't have a packed layout in memory, fall back to MarshalBytes.
+ buf := task.CopyScratchBuffer(s.SizeBytes())
+ s.MarshalBytes(buf)
+ return task.CopyOutBytes(addr, buf)
+ }
+
+ // Bypass escape analysis on s. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on s.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(s)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by s's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = s.SizeBytes()
+ hdr.Cap = s.SizeBytes()
+
+ len, err := task.CopyOutBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that s
+ // must live until after the CopyOutBytes.
+ runtime.KeepAlive(s)
+ return len, err
+}
+
+// CopyIn implements marshal.Marshallable.CopyIn.
+func (s *Stat) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
+ if !s.MTime.Packed() && s.CTime.Packed() && s.ATime.Packed() {
+ // Type Stat doesn't have a packed layout in memory, fall back to UnmarshalBytes.
+ buf := task.CopyScratchBuffer(s.SizeBytes())
+ n, err := task.CopyInBytes(addr, buf)
+ if err != nil {
+ return n, err
+ }
+ s.UnmarshalBytes(buf)
+ return n, nil
+ }
+
+ // Bypass escape analysis on s. The no-op arithmetic operation on the
+ // pointer makes the compiler think val doesn't depend on s.
+ // See src/runtime/stubs.go:noescape() in the golang toolchain.
+ ptr := unsafe.Pointer(s)
+ val := uintptr(ptr)
+ val = val^0
+
+ // Construct a slice backed by s's underlying memory.
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = val
+ hdr.Len = s.SizeBytes()
+ hdr.Cap = s.SizeBytes()
+
+ len, err := task.CopyInBytes(addr, buf)
+ // Since we bypassed the compiler's escape analysis, indicate that s
+ // must live until after the CopyInBytes.
+ runtime.KeepAlive(s)
+ return len, err
+}
+
diff --git a/pkg/abi/linux/time.go b/pkg/abi/linux/time.go
index 5c5a58cd4..e562b46d9 100644
--- a/pkg/abi/linux/time.go
+++ b/pkg/abi/linux/time.go
@@ -101,6 +101,8 @@ func NsecToTimeT(nsec int64) TimeT {
}
// Timespec represents struct timespec in <time.h>.
+//
+// +marshal
type Timespec struct {
Sec int64
Nsec int64
diff --git a/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go b/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go
index a98193a5b..a5f55a80b 100755
--- a/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go
@@ -1,6 +1,5 @@
// automatically generated by stateify.
// +build amd64
-// +build amd64
package linux
diff --git a/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go b/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go
index b144adbda..7b31374fe 100755
--- a/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go
@@ -1,6 +1,5 @@
// automatically generated by stateify.
// +build arm64
-// +build arm64
package linux
diff --git a/pkg/sentry/syscalls/linux/sys_stat.go b/pkg/sentry/syscalls/linux/sys_stat.go
index c841abccb..8b66a9006 100644
--- a/pkg/sentry/syscalls/linux/sys_stat.go
+++ b/pkg/sentry/syscalls/linux/sys_stat.go
@@ -23,6 +23,24 @@ import (
"gvisor.dev/gvisor/pkg/usermem"
)
+func statFromAttrs(t *kernel.Task, sattr fs.StableAttr, uattr fs.UnstableAttr) linux.Stat {
+ return linux.Stat{
+ Dev: sattr.DeviceID,
+ Ino: sattr.InodeID,
+ Nlink: uattr.Links,
+ Mode: sattr.Type.LinuxType() | uint32(uattr.Perms.LinuxMode()),
+ UID: uint32(uattr.Owner.UID.In(t.UserNamespace()).OrOverflow()),
+ GID: uint32(uattr.Owner.GID.In(t.UserNamespace()).OrOverflow()),
+ Rdev: uint64(linux.MakeDeviceID(sattr.DeviceFileMajor, sattr.DeviceFileMinor)),
+ Size: uattr.Size,
+ Blksize: sattr.BlockSize,
+ Blocks: uattr.Usage / 512,
+ ATime: uattr.AccessTime.Timespec(),
+ MTime: uattr.ModificationTime.Timespec(),
+ CTime: uattr.StatusChangeTime.Timespec(),
+ }
+}
+
// Stat implements linux syscall stat(2).
func Stat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
addr := args[0].Pointer()
@@ -112,7 +130,9 @@ func stat(t *kernel.Task, d *fs.Dirent, dirPath bool, statAddr usermem.Addr) err
if err != nil {
return err
}
- return copyOutStat(t, statAddr, d.Inode.StableAttr, uattr)
+ s := statFromAttrs(t, d.Inode.StableAttr, uattr)
+ _, err = s.CopyOut(t, statAddr)
+ return err
}
// fstat implements fstat for the given *fs.File.
@@ -121,7 +141,9 @@ func fstat(t *kernel.Task, f *fs.File, statAddr usermem.Addr) error {
if err != nil {
return err
}
- return copyOutStat(t, statAddr, f.Dirent.Inode.StableAttr, uattr)
+ s := statFromAttrs(t, f.Dirent.Inode.StableAttr, uattr)
+ _, err = s.CopyOut(t, statAddr)
+ return err
}
// Statx implements linux syscall statx(2).
diff --git a/pkg/sentry/syscalls/linux/sys_stat_amd64.go b/pkg/sentry/syscalls/linux/sys_stat_amd64.go
deleted file mode 100755
index 75a567bd4..000000000
--- a/pkg/sentry/syscalls/linux/sys_stat_amd64.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 linux
-
-import (
- "gvisor.dev/gvisor/pkg/abi/linux"
- "gvisor.dev/gvisor/pkg/binary"
- "gvisor.dev/gvisor/pkg/sentry/fs"
- "gvisor.dev/gvisor/pkg/sentry/kernel"
- "gvisor.dev/gvisor/pkg/usermem"
-)
-
-// copyOutStat copies the attributes (sattr, uattr) to the struct stat at
-// address dst in t's address space. It encodes the stat struct to bytes
-// manually, as stat() is a very common syscall for many applications, and
-// t.CopyObjectOut has noticeable performance impact due to its many slice
-// allocations and use of reflection.
-func copyOutStat(t *kernel.Task, dst usermem.Addr, sattr fs.StableAttr, uattr fs.UnstableAttr) error {
- b := t.CopyScratchBuffer(int(linux.SizeOfStat))[:0]
-
- // Dev (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.DeviceID))
- // Ino (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.InodeID))
- // Nlink (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uattr.Links)
- // Mode (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, sattr.Type.LinuxType()|uint32(uattr.Perms.LinuxMode()))
- // UID (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.UID.In(t.UserNamespace()).OrOverflow()))
- // GID (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.GID.In(t.UserNamespace()).OrOverflow()))
- // Padding (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, 0)
- // Rdev (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(linux.MakeDeviceID(sattr.DeviceFileMajor, sattr.DeviceFileMinor)))
- // Size (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Size))
- // Blksize (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.BlockSize))
- // Blocks (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Usage/512))
-
- // ATime
- atime := uattr.AccessTime.Timespec()
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Sec))
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Nsec))
-
- // MTime
- mtime := uattr.ModificationTime.Timespec()
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Sec))
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Nsec))
-
- // CTime
- ctime := uattr.StatusChangeTime.Timespec()
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Sec))
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Nsec))
-
- _, err := t.CopyOutBytes(dst, b)
- return err
-}
diff --git a/pkg/sentry/syscalls/linux/sys_stat_arm64.go b/pkg/sentry/syscalls/linux/sys_stat_arm64.go
deleted file mode 100755
index 80c98d05c..000000000
--- a/pkg/sentry/syscalls/linux/sys_stat_arm64.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 arm64
-
-package linux
-
-import (
- "gvisor.dev/gvisor/pkg/abi/linux"
- "gvisor.dev/gvisor/pkg/binary"
- "gvisor.dev/gvisor/pkg/sentry/fs"
- "gvisor.dev/gvisor/pkg/sentry/kernel"
- "gvisor.dev/gvisor/pkg/usermem"
-)
-
-// copyOutStat copies the attributes (sattr, uattr) to the struct stat at
-// address dst in t's address space. It encodes the stat struct to bytes
-// manually, as stat() is a very common syscall for many applications, and
-// t.CopyObjectOut has noticeable performance impact due to its many slice
-// allocations and use of reflection.
-func copyOutStat(t *kernel.Task, dst usermem.Addr, sattr fs.StableAttr, uattr fs.UnstableAttr) error {
- b := t.CopyScratchBuffer(int(linux.SizeOfStat))[:0]
-
- // Dev (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.DeviceID))
- // Ino (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.InodeID))
- // Mode (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, sattr.Type.LinuxType()|uint32(uattr.Perms.LinuxMode()))
- // Nlink (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Links))
- // UID (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.UID.In(t.UserNamespace()).OrOverflow()))
- // GID (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.GID.In(t.UserNamespace()).OrOverflow()))
- // Rdev (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(linux.MakeDeviceID(sattr.DeviceFileMajor, sattr.DeviceFileMinor)))
- // Padding (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, 0)
- // Size (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Size))
- // Blksize (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, uint32(sattr.BlockSize))
- // Padding (uint32)
- b = binary.AppendUint32(b, usermem.ByteOrder, 0)
- // Blocks (uint64)
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Usage/512))
-
- // ATime
- atime := uattr.AccessTime.Timespec()
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Sec))
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Nsec))
-
- // MTime
- mtime := uattr.ModificationTime.Timespec()
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Sec))
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Nsec))
-
- // CTime
- ctime := uattr.StatusChangeTime.Timespec()
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Sec))
- b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Nsec))
-
- _, err := t.CopyOutBytes(dst, b)
- return err
-}
diff --git a/tools/go_marshal/marshal/marshal.go b/tools/go_marshal/marshal/marshal.go
new file mode 100755
index 000000000..10614ec4d
--- /dev/null
+++ b/tools/go_marshal/marshal/marshal.go
@@ -0,0 +1,94 @@
+// Copyright 2019 The gVisor Authors.
+//
+// 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 marshal defines the Marshallable interface for
+// serialize/deserializing go data structures to/from memory, according to the
+// Linux ABI.
+//
+// Implementations of this interface are typically automatically generated by
+// tools/go_marshal. See the go_marshal README for details.
+package marshal
+
+import (
+ "gvisor.dev/gvisor/pkg/usermem"
+)
+
+// Task provides a subset of kernel.Task, used in marshalling. We don't import
+// the kernel package directly to avoid circular dependency.
+type Task interface {
+ // CopyScratchBuffer provides a task goroutine-local scratch buffer. See
+ // kernel.CopyScratchBuffer.
+ CopyScratchBuffer(size int) []byte
+
+ // CopyOutBytes writes the contents of b to the task's memory. See
+ // kernel.CopyOutBytes.
+ CopyOutBytes(addr usermem.Addr, b []byte) (int, error)
+
+ // CopyInBytes reads the contents of the task's memory to b. See
+ // kernel.CopyInBytes.
+ CopyInBytes(addr usermem.Addr, b []byte) (int, error)
+}
+
+// Marshallable represents a type that can be marshalled to and from memory.
+type Marshallable interface {
+ // SizeBytes is the size of the memory representation of a type in
+ // marshalled form.
+ SizeBytes() int
+
+ // MarshalBytes serializes a copy of a type to dst. dst must be at least
+ // SizeBytes() long.
+ MarshalBytes(dst []byte)
+
+ // UnmarshalBytes deserializes a type from src. src must be at least
+ // SizeBytes() long.
+ UnmarshalBytes(src []byte)
+
+ // Packed returns true if the marshalled size of the type is the same as the
+ // size it occupies in memory. This happens when the type has no fields
+ // starting at unaligned addresses (should always be true by default for ABI
+ // structs, verified by automatically generated tests when using
+ // go_marshal), and has no fields marked `marshal:"unaligned"`.
+ Packed() bool
+
+ // MarshalUnsafe serializes a type by bulk copying its in-memory
+ // representation to the dst buffer. This is only safe to do when the type
+ // has no implicit padding, see Marshallable.Packed. When Packed would
+ // return false, MarshalUnsafe should fall back to the safer but slower
+ // MarshalBytes.
+ MarshalUnsafe(dst []byte)
+
+ // UnmarshalUnsafe deserializes a type by directly copying to the underlying
+ // memory allocated for the object by the runtime.
+ //
+ // This allows much faster unmarshalling of types which have no implicit
+ // padding, see Marshallable.Packed. When Packed would return false,
+ // UnmarshalUnsafe should fall back to the safer but slower unmarshal
+ // mechanism implemented in UnmarshalBytes.
+ UnmarshalUnsafe(src []byte)
+
+ // CopyIn deserializes a Marshallable type from a task's memory. This may
+ // only be called from a task goroutine. This is more efficient than calling
+ // UnmarshalUnsafe on Marshallable.Packed types, as the type being
+ // marshalled does not escape. The implementation should avoid creating
+ // extra copies in memory by directly deserializing to the object's
+ // underlying memory.
+ CopyIn(task Task, addr usermem.Addr) (int, error)
+
+ // CopyOut serializes a Marshallable type to a task's memory. This may only
+ // be called from a task goroutine. This is more efficient than calling
+ // MarshalUnsafe on Marshallable.Packed types, as the type being serialized
+ // does not escape. The implementation should avoid creating extra copies in
+ // memory by directly serializing from the object's underlying memory.
+ CopyOut(task Task, addr usermem.Addr) (int, error)
+}
diff --git a/tools/go_marshal/marshal/marshal_state_autogen.go b/tools/go_marshal/marshal/marshal_state_autogen.go
new file mode 100755
index 000000000..a0a953158
--- /dev/null
+++ b/tools/go_marshal/marshal/marshal_state_autogen.go
@@ -0,0 +1,3 @@
+// automatically generated by stateify.
+
+package marshal