Format struct pollfd in poll(2)/ppoll(2)
I0410 15:40:38.854295 3776 x:0] [ 1] poll_test E poll(0x2b00bfb5c020 [{FD: 0x3 anon_inode:[eventfd], Events: POLLOUT, REvents: ...}], 0x1, 0x1) I0410 15:40:38.854348 3776 x:0] [ 1] poll_test X poll(0x2b00bfb5c020 [{FD: 0x3 anon_inode:[eventfd], Events: POLLOUT|POLLERR|POLLHUP, REvents: POLLOUT}], 0x1, 0x1) = 0x1 (10.765?s) PiperOrigin-RevId: 244269879 Change-Id: If07ba54a486fdeaaedfc0123769b78d1da862307
This commit is contained in:
parent
ce64d9ebf0
commit
c931c8e082
|
@ -11,6 +11,7 @@ go_library(
|
|||
"futex.go",
|
||||
"linux64.go",
|
||||
"open.go",
|
||||
"poll.go",
|
||||
"ptrace.go",
|
||||
"signal.go",
|
||||
"socket.go",
|
||||
|
|
|
@ -24,7 +24,7 @@ var linuxAMD64 = SyscallMap{
|
|||
4: makeSyscallInfo("stat", Path, Stat),
|
||||
5: makeSyscallInfo("fstat", FD, Stat),
|
||||
6: makeSyscallInfo("lstat", Path, Stat),
|
||||
7: makeSyscallInfo("poll", Hex, Hex, Hex),
|
||||
7: makeSyscallInfo("poll", PollFDs, Hex, Hex),
|
||||
8: makeSyscallInfo("lseek", Hex, Hex, Hex),
|
||||
9: makeSyscallInfo("mmap", Hex, Hex, Hex, Hex, FD, Hex),
|
||||
10: makeSyscallInfo("mprotect", Hex, Hex, Hex),
|
||||
|
@ -288,7 +288,7 @@ var linuxAMD64 = SyscallMap{
|
|||
268: makeSyscallInfo("fchmodat", FD, Path, Mode),
|
||||
269: makeSyscallInfo("faccessat", FD, Path, Oct, Hex),
|
||||
270: makeSyscallInfo("pselect6", Hex, Hex, Hex, Hex, Hex, Hex),
|
||||
271: makeSyscallInfo("ppoll", Hex, Hex, Timespec, SigSet, Hex),
|
||||
271: makeSyscallInfo("ppoll", PollFDs, Hex, Timespec, SigSet, Hex),
|
||||
272: makeSyscallInfo("unshare", CloneFlags),
|
||||
273: makeSyscallInfo("set_robust_list", Hex, Hex),
|
||||
274: makeSyscallInfo("get_robust_list", Hex, Hex, Hex),
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// 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"
|
||||
"strings"
|
||||
|
||||
"gvisor.googlesource.com/gvisor/pkg/abi"
|
||||
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
|
||||
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs"
|
||||
slinux "gvisor.googlesource.com/gvisor/pkg/sentry/syscalls/linux"
|
||||
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
|
||||
)
|
||||
|
||||
// PollEventSet is the set of poll(2) event flags.
|
||||
var PollEventSet = abi.FlagSet{
|
||||
{Flag: linux.POLLIN, Name: "POLLIN"},
|
||||
{Flag: linux.POLLPRI, Name: "POLLPRI"},
|
||||
{Flag: linux.POLLOUT, Name: "POLLOUT"},
|
||||
{Flag: linux.POLLERR, Name: "POLLERR"},
|
||||
{Flag: linux.POLLHUP, Name: "POLLHUP"},
|
||||
{Flag: linux.POLLNVAL, Name: "POLLNVAL"},
|
||||
{Flag: linux.POLLRDNORM, Name: "POLLRDNORM"},
|
||||
{Flag: linux.POLLRDBAND, Name: "POLLRDBAND"},
|
||||
{Flag: linux.POLLWRNORM, Name: "POLLWRNORM"},
|
||||
{Flag: linux.POLLWRBAND, Name: "POLLWRBAND"},
|
||||
{Flag: linux.POLLMSG, Name: "POLLMSG"},
|
||||
{Flag: linux.POLLREMOVE, Name: "POLLREMOVE"},
|
||||
{Flag: linux.POLLRDHUP, Name: "POLLRDHUP"},
|
||||
{Flag: linux.POLLFREE, Name: "POLLFREE"},
|
||||
{Flag: linux.POLL_BUSY_LOOP, Name: "POLL_BUSY_LOOP"},
|
||||
}
|
||||
|
||||
func pollFD(t *kernel.Task, pfd *linux.PollFD, post bool) string {
|
||||
revents := "..."
|
||||
if post {
|
||||
revents = PollEventSet.Parse(uint64(pfd.REvents))
|
||||
}
|
||||
return fmt.Sprintf("{FD: %s, Events: %s, REvents: %s}", fd(t, kdefs.FD(pfd.FD)), PollEventSet.Parse(uint64(pfd.Events)), revents)
|
||||
}
|
||||
|
||||
func pollFDs(t *kernel.Task, addr usermem.Addr, nfds uint, post bool) string {
|
||||
if addr == 0 {
|
||||
return "null"
|
||||
}
|
||||
|
||||
pfds, err := slinux.CopyInPollFDs(t, addr, nfds)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("%#x (error decoding pollfds: %s)", addr, err)
|
||||
}
|
||||
|
||||
s := make([]string, 0, len(pfds))
|
||||
for i := range pfds {
|
||||
s = append(s, pollFD(t, &pfds[i], post))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#x [%s]", addr, strings.Join(s, ", "))
|
||||
}
|
|
@ -438,6 +438,8 @@ func (i *SyscallInfo) pre(t *kernel.Task, args arch.SyscallArguments, maximumBlo
|
|||
output = append(output, capHeader(t, args[arg].Pointer()))
|
||||
case CapData:
|
||||
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 Oct:
|
||||
output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8))
|
||||
case Hex:
|
||||
|
@ -502,6 +504,8 @@ func (i *SyscallInfo) post(t *kernel.Task, args arch.SyscallArguments, rval uint
|
|||
output[arg] = sigAction(t, args[arg].Pointer())
|
||||
case PostCapData:
|
||||
output[arg] = capData(t, args[arg-1].Pointer(), args[arg].Pointer())
|
||||
case PollFDs:
|
||||
output[arg] = pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,6 +202,10 @@ const (
|
|||
// PostCapData is the data argument to capget(2)/capset(2), formatted
|
||||
// after syscall execution. The previous argument must be CapHeader.
|
||||
PostCapData
|
||||
|
||||
// PollFDs is an array of struct pollfd. The number of entries in the
|
||||
// array is in the next argument.
|
||||
PollFDs
|
||||
)
|
||||
|
||||
// defaultFormat is the syscall argument format to use if the actual format is
|
||||
|
|
|
@ -155,18 +155,28 @@ func pollBlock(t *kernel.Task, pfd []linux.PollFD, timeout time.Duration) (time.
|
|||
return timeout, n, nil
|
||||
}
|
||||
|
||||
func doPoll(t *kernel.Task, pfdAddr usermem.Addr, nfds uint, timeout time.Duration) (time.Duration, uintptr, error) {
|
||||
// CopyInPollFDs copies an array of struct pollfd unless nfds exceeds the max.
|
||||
func CopyInPollFDs(t *kernel.Task, addr usermem.Addr, nfds uint) ([]linux.PollFD, error) {
|
||||
if uint64(nfds) > t.ThreadGroup().Limits().GetCapped(limits.NumberOfFiles, fileCap) {
|
||||
return timeout, 0, syserror.EINVAL
|
||||
return nil, syserror.EINVAL
|
||||
}
|
||||
|
||||
pfd := make([]linux.PollFD, nfds)
|
||||
if nfds > 0 {
|
||||
if _, err := t.CopyIn(pfdAddr, &pfd); err != nil {
|
||||
return timeout, 0, err
|
||||
if _, err := t.CopyIn(addr, &pfd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return pfd, nil
|
||||
}
|
||||
|
||||
func doPoll(t *kernel.Task, addr usermem.Addr, nfds uint, timeout time.Duration) (time.Duration, uintptr, error) {
|
||||
pfd, err := CopyInPollFDs(t, addr, nfds)
|
||||
if err != nil {
|
||||
return timeout, 0, err
|
||||
}
|
||||
|
||||
// Compatibility warning: Linux adds POLLHUP and POLLERR just before
|
||||
// polling, in fs/select.c:do_pollfd(). Since pfd is copied out after
|
||||
// polling, changing event masks here is an application-visible difference.
|
||||
|
@ -180,7 +190,7 @@ func doPoll(t *kernel.Task, pfdAddr usermem.Addr, nfds uint, timeout time.Durati
|
|||
// The poll entries are copied out regardless of whether
|
||||
// any are set or not. This aligns with the Linux behavior.
|
||||
if nfds > 0 && err == nil {
|
||||
if _, err := t.CopyOut(pfdAddr, pfd); err != nil {
|
||||
if _, err := t.CopyOut(addr, pfd); err != nil {
|
||||
return remainingTimeout, 0, err
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue