mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
@@ -14,6 +14,7 @@ go_library(
|
||||
"open.go",
|
||||
"poll.go",
|
||||
"ptrace.go",
|
||||
"select.go",
|
||||
"signal.go",
|
||||
"socket.go",
|
||||
"strace.go",
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user