Format fd_set parameters in select(2)/pselect(2) for strace.

I1202 14:55:06.835076    7991 x:0] [   1] select_test E
  select(0xa, 0x7fc6ce924c28 [0 1], null, null, 0x7fc6ce924c08 {sec=0 usec=0})
I1202 14:55:06.835102    7991 x:0] [   1] select_test X
  select(0xa, 0x7fc6ce924c28 [0 1], null, null, 0x7fc6ce924c08 {sec=0 usec=0})

PiperOrigin-RevId: 284831805
This commit is contained in:
Dean Deng
2019-12-10 13:06:01 -08:00
committed by gVisor bot
parent 769e1cdcbe
commit 39386d78bb
6 changed files with 96 additions and 39 deletions
+1
View File
@@ -14,6 +14,7 @@ go_library(
"open.go",
"poll.go",
"ptrace.go",
"select.go",
"signal.go",
"socket.go",
"strace.go",
+2 -2
View File
@@ -40,7 +40,7 @@ var linuxAMD64 = SyscallMap{
20: makeSyscallInfo("writev", FD, WriteIOVec, Hex),
21: makeSyscallInfo("access", Path, Oct),
22: makeSyscallInfo("pipe", PipeFDs),
23: makeSyscallInfo("select", Hex, Hex, Hex, Hex, Timeval),
23: makeSyscallInfo("select", Hex, SelectFDSet, SelectFDSet, SelectFDSet, Timeval),
24: makeSyscallInfo("sched_yield"),
25: makeSyscallInfo("mremap", Hex, Hex, Hex, Hex, Hex),
26: makeSyscallInfo("msync", Hex, Hex, Hex),
@@ -287,7 +287,7 @@ var linuxAMD64 = SyscallMap{
267: makeSyscallInfo("readlinkat", FD, Path, ReadBuffer, Hex),
268: makeSyscallInfo("fchmodat", FD, Path, Mode),
269: makeSyscallInfo("faccessat", FD, Path, Oct, Hex),
270: makeSyscallInfo("pselect6", Hex, Hex, Hex, Hex, Hex, Hex),
270: makeSyscallInfo("pselect6", Hex, SelectFDSet, SelectFDSet, SelectFDSet, Timespec, SigSet),
271: makeSyscallInfo("ppoll", PollFDs, Hex, Timespec, SigSet, Hex),
272: makeSyscallInfo("unshare", CloneFlags),
273: makeSyscallInfo("set_robust_list", Hex, Hex),
+53
View File
@@ -0,0 +1,53 @@
// 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 strace
import (
"fmt"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/syscalls/linux"
"gvisor.dev/gvisor/pkg/sentry/usermem"
)
func fdsFromSet(t *kernel.Task, set []byte) []int {
var fds []int
// Append n if the n-th bit is 1.
for i, v := range set {
for j := 0; j < 8; j++ {
if (v>>uint(j))&1 == 1 {
fds = append(fds, i*8+j)
}
}
}
return fds
}
func fdSet(t *kernel.Task, nfds int, addr usermem.Addr) string {
if addr == 0 {
return "null"
}
// Calculate the size of the fd set (one bit per fd).
nBytes := (nfds + 7) / 8
nBitsInLastPartialByte := uint(nfds % 8)
set, err := linux.CopyInFDSet(t, addr, nBytes, nBitsInLastPartialByte)
if err != nil {
return fmt.Sprintf("%#x (error decoding fdset: %s)", addr, err)
}
return fmt.Sprintf("%#x %v", addr, fdsFromSet(t, set))
}
+2
View File
@@ -439,6 +439,8 @@ func (i *SyscallInfo) pre(t *kernel.Task, args arch.SyscallArguments, maximumBlo
output = append(output, capData(t, args[arg-1].Pointer(), args[arg].Pointer()))
case PollFDs:
output = append(output, pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), false))
case SelectFDSet:
output = append(output, fdSet(t, int(args[0].Int()), args[arg].Pointer()))
case Oct:
output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8))
case Hex:
+4
View File
@@ -206,6 +206,10 @@ const (
// PollFDs is an array of struct pollfd. The number of entries in the
// array is in the next argument.
PollFDs
// SelectFDSet is an fd_set argument in select(2)/pselect(2). The number of
// fds represented must be the first argument.
SelectFDSet
)
// defaultFormat is the syscall argument format to use if the actual format is
+34 -37
View File
@@ -197,53 +197,51 @@ func doPoll(t *kernel.Task, addr usermem.Addr, nfds uint, timeout time.Duration)
return remainingTimeout, n, err
}
// CopyInFDSet copies an fd set from select(2)/pselect(2).
func CopyInFDSet(t *kernel.Task, addr usermem.Addr, nBytes int, nBitsInLastPartialByte uint) ([]byte, error) {
set := make([]byte, nBytes)
if addr != 0 {
if _, err := t.CopyIn(addr, &set); err != nil {
return nil, err
}
// If we only use part of the last byte, mask out the extraneous bits.
//
// N.B. This only works on little-endian architectures.
if nBitsInLastPartialByte != 0 {
set[nBytes-1] &^= byte(0xff) << nBitsInLastPartialByte
}
}
return set, nil
}
func doSelect(t *kernel.Task, nfds int, readFDs, writeFDs, exceptFDs usermem.Addr, timeout time.Duration) (uintptr, error) {
if nfds < 0 || nfds > fileCap {
return 0, syserror.EINVAL
}
// Calculate the size of the fd sets (one bit per fd).
nBytes := (nfds + 7) / 8
nBitsInLastPartialByte := uint(nfds % 8)
// Capture all the provided input vectors.
//
// N.B. This only works on little-endian architectures.
byteCount := (nfds + 7) / 8
bitsInLastPartialByte := uint(nfds % 8)
r := make([]byte, byteCount)
w := make([]byte, byteCount)
e := make([]byte, byteCount)
if readFDs != 0 {
if _, err := t.CopyIn(readFDs, &r); err != nil {
return 0, err
}
// Mask out bits above nfds.
if bitsInLastPartialByte != 0 {
r[byteCount-1] &^= byte(0xff) << bitsInLastPartialByte
}
r, err := CopyInFDSet(t, readFDs, nBytes, nBitsInLastPartialByte)
if err != nil {
return 0, err
}
if writeFDs != 0 {
if _, err := t.CopyIn(writeFDs, &w); err != nil {
return 0, err
}
if bitsInLastPartialByte != 0 {
w[byteCount-1] &^= byte(0xff) << bitsInLastPartialByte
}
w, err := CopyInFDSet(t, writeFDs, nBytes, nBitsInLastPartialByte)
if err != nil {
return 0, err
}
if exceptFDs != 0 {
if _, err := t.CopyIn(exceptFDs, &e); err != nil {
return 0, err
}
if bitsInLastPartialByte != 0 {
e[byteCount-1] &^= byte(0xff) << bitsInLastPartialByte
}
e, err := CopyInFDSet(t, exceptFDs, nBytes, nBitsInLastPartialByte)
if err != nil {
return 0, err
}
// Count how many FDs are actually being requested so that we can build
// a PollFD array.
fdCount := 0
for i := 0; i < byteCount; i++ {
for i := 0; i < nBytes; i++ {
v := r[i] | w[i] | e[i]
for v != 0 {
v &= (v - 1)
@@ -254,7 +252,7 @@ func doSelect(t *kernel.Task, nfds int, readFDs, writeFDs, exceptFDs usermem.Add
// Build the PollFD array.
pfd := make([]linux.PollFD, 0, fdCount)
var fd int32
for i := 0; i < byteCount; i++ {
for i := 0; i < nBytes; i++ {
rV, wV, eV := r[i], w[i], e[i]
v := rV | wV | eV
m := byte(1)
@@ -295,8 +293,7 @@ func doSelect(t *kernel.Task, nfds int, readFDs, writeFDs, exceptFDs usermem.Add
}
// Do the syscall, then count the number of bits set.
_, _, err := pollBlock(t, pfd, timeout)
if err != nil {
if _, _, err = pollBlock(t, pfd, timeout); err != nil {
return 0, syserror.ConvertIntr(err, syserror.EINTR)
}