Better strace logging for epoll syscalls.

Example:

epoll_ctl(0x3 anon_inode:[eventpoll], EPOLL_CTL_ADD, 0x6 anon_inode:[eventfd], 0x7efe2fd92a80 {events=EPOLLIN|EPOLLOUT data=0x10203040506070a}) = 0x0 (4.411µs)

epoll_wait(0x3 anon_inode:[eventpoll], 0x7efe2fd92b50 {{events=EPOLLOUT data=0x102030405060708}{events=EPOLLOUT data=0x102030405060708}{events=EPOLLOUT data=0x102030405060708}}, 0x3, 0xffffffff) = 0x3 (29.891µs)

PiperOrigin-RevId: 296258146
This commit is contained in:
gVisor bot 2020-02-20 11:29:59 -08:00 committed by Copybara-Service
parent 9a4e3e63ef
commit 9bad87339a
7 changed files with 120 additions and 5 deletions

View File

@ -14,6 +14,10 @@
package linux
import (
"gvisor.dev/gvisor/pkg/binary"
)
// Event masks.
const (
EPOLLIN = 0x1
@ -53,3 +57,6 @@ const (
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
)
// SizeOfEpollEvent is the size of EpollEvent struct.
var SizeOfEpollEvent = int(binary.Size(EpollEvent{}))

View File

@ -7,6 +7,7 @@ go_library(
srcs = [
"capability.go",
"clone.go",
"epoll.go",
"futex.go",
"linux64_amd64.go",
"linux64_arm64.go",

View File

@ -0,0 +1,89 @@
// 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.
package strace
import (
"fmt"
"strings"
"gvisor.dev/gvisor/pkg/abi"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/usermem"
)
func epollEvent(t *kernel.Task, eventAddr usermem.Addr) string {
var e linux.EpollEvent
if _, err := t.CopyIn(eventAddr, &e); err != nil {
return fmt.Sprintf("%#x {error reading event: %v}", eventAddr, err)
}
var sb strings.Builder
fmt.Fprintf(&sb, "%#x ", eventAddr)
writeEpollEvent(&sb, e)
return sb.String()
}
func epollEvents(t *kernel.Task, eventsAddr usermem.Addr, numEvents, maxBytes uint64) string {
var sb strings.Builder
fmt.Fprintf(&sb, "%#x {", eventsAddr)
addr := eventsAddr
for i := uint64(0); i < numEvents; i++ {
var e linux.EpollEvent
if _, err := t.CopyIn(addr, &e); err != nil {
fmt.Fprintf(&sb, "{error reading event at %#x: %v}", addr, err)
continue
}
writeEpollEvent(&sb, e)
if uint64(sb.Len()) >= maxBytes {
sb.WriteString("...")
break
}
if _, ok := addr.AddLength(uint64(linux.SizeOfEpollEvent)); !ok {
fmt.Fprintf(&sb, "{error reading event at %#x: EFAULT}", addr)
continue
}
}
sb.WriteString("}")
return sb.String()
}
func writeEpollEvent(sb *strings.Builder, e linux.EpollEvent) {
events := epollEventEvents.Parse(uint64(e.Events))
fmt.Fprintf(sb, "{events=%s data=[%#x, %#x]}", events, e.Data[0], e.Data[1])
}
var epollCtlOps = abi.ValueSet{
linux.EPOLL_CTL_ADD: "EPOLL_CTL_ADD",
linux.EPOLL_CTL_DEL: "EPOLL_CTL_DEL",
linux.EPOLL_CTL_MOD: "EPOLL_CTL_MOD",
}
var epollEventEvents = abi.FlagSet{
{Flag: linux.EPOLLIN, Name: "EPOLLIN"},
{Flag: linux.EPOLLPRI, Name: "EPOLLPRI"},
{Flag: linux.EPOLLOUT, Name: "EPOLLOUT"},
{Flag: linux.EPOLLERR, Name: "EPOLLERR"},
{Flag: linux.EPOLLHUP, Name: "EPULLHUP"},
{Flag: linux.EPOLLRDNORM, Name: "EPOLLRDNORM"},
{Flag: linux.EPOLLRDBAND, Name: "EPOLLRDBAND"},
{Flag: linux.EPOLLWRNORM, Name: "EPOLLWRNORM"},
{Flag: linux.EPOLLWRBAND, Name: "EPOLLWRBAND"},
{Flag: linux.EPOLLMSG, Name: "EPOLLMSG"},
{Flag: linux.EPOLLRDHUP, Name: "EPOLLRDHUP"},
{Flag: linux.EPOLLEXCLUSIVE, Name: "EPOLLEXCLUSIVE"},
{Flag: linux.EPOLLWAKEUP, Name: "EPOLLWAKEUP"},
{Flag: linux.EPOLLONESHOT, Name: "EPOLLONESHOT"},
{Flag: linux.EPOLLET, Name: "EPOLLET"},
}

View File

@ -256,8 +256,8 @@ var linuxAMD64 = SyscallMap{
229: makeSyscallInfo("clock_getres", Hex, PostTimespec),
230: makeSyscallInfo("clock_nanosleep", Hex, Hex, Timespec, PostTimespec),
231: makeSyscallInfo("exit_group", Hex),
232: makeSyscallInfo("epoll_wait", Hex, Hex, Hex, Hex),
233: makeSyscallInfo("epoll_ctl", Hex, Hex, FD, Hex),
232: makeSyscallInfo("epoll_wait", FD, EpollEvents, Hex, Hex),
233: makeSyscallInfo("epoll_ctl", FD, EpollCtlOp, FD, EpollEvent),
234: makeSyscallInfo("tgkill", Hex, Hex, Signal),
235: makeSyscallInfo("utimes", Path, Timeval),
// 236: vserver (not implemented in the Linux kernel)
@ -305,7 +305,7 @@ var linuxAMD64 = SyscallMap{
278: makeSyscallInfo("vmsplice", FD, Hex, Hex, Hex),
279: makeSyscallInfo("move_pages", Hex, Hex, Hex, Hex, Hex, Hex),
280: makeSyscallInfo("utimensat", FD, Path, UTimeTimespec, Hex),
281: makeSyscallInfo("epoll_pwait", Hex, Hex, Hex, Hex, SigSet, Hex),
281: makeSyscallInfo("epoll_pwait", FD, EpollEvents, Hex, Hex, SigSet, Hex),
282: makeSyscallInfo("signalfd", Hex, Hex, Hex),
283: makeSyscallInfo("timerfd_create", Hex, Hex),
284: makeSyscallInfo("eventfd", Hex),

View File

@ -45,8 +45,8 @@ var linuxARM64 = SyscallMap{
18: makeSyscallInfo("lookup_dcookie", Hex, Hex, Hex),
19: makeSyscallInfo("eventfd2", Hex, Hex),
20: makeSyscallInfo("epoll_create1", Hex),
21: makeSyscallInfo("epoll_ctl", Hex, Hex, FD, Hex),
22: makeSyscallInfo("epoll_pwait", Hex, Hex, Hex, Hex, SigSet, Hex),
21: makeSyscallInfo("epoll_ctl", FD, EpollCtlOp, FD, EpollEvent),
22: makeSyscallInfo("epoll_pwait", FD, EpollEvents, Hex, Hex, SigSet, Hex),
23: makeSyscallInfo("dup", FD),
24: makeSyscallInfo("dup3", FD, FD, Hex),
25: makeSyscallInfo("fcntl", FD, Hex, Hex),

View File

@ -481,6 +481,12 @@ 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 EpollCtlOp:
output = append(output, epollCtlOps.Parse(uint64(args[arg].Int())))
case EpollEvent:
output = append(output, epollEvent(t, args[arg].Pointer()))
case EpollEvents:
output = append(output, epollEvents(t, args[arg].Pointer(), 0 /* numEvents */, uint64(maximumBlobSize)))
case SelectFDSet:
output = append(output, fdSet(t, int(args[0].Int()), args[arg].Pointer()))
case Oct:
@ -549,6 +555,8 @@ func (i *SyscallInfo) post(t *kernel.Task, args arch.SyscallArguments, rval uint
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)
case EpollEvents:
output[arg] = epollEvents(t, args[arg].Pointer(), uint64(rval), uint64(maximumBlobSize))
case GetSockOptVal:
output[arg] = getSockOptVal(t, args[arg-2].Uint64() /* level */, args[arg-1].Uint64() /* optName */, args[arg].Pointer() /* optVal */, args[arg+1].Pointer() /* optLen */, maximumBlobSize, rval)
case SetSockOptVal:

View File

@ -228,6 +228,16 @@ const (
// SockOptLevel is the optname argument in getsockopt(2) and
// setsockopt(2).
SockOptName
// EpollCtlOp is the op argument to epoll_ctl(2).
EpollCtlOp
// EpollEvent is the event argument in epoll_ctl(2).
EpollEvent
// EpollEvents is an array of struct epoll_event. It is the events
// argument in epoll_wait(2)/epoll_pwait(2).
EpollEvents
)
// defaultFormat is the syscall argument format to use if the actual format is