strace/io.c
Dmitry V. Levin b93d52fe3d Change the license of strace to LGPL-2.1-or-later
strace is now provided under the terms of the GNU Lesser General
Public License version 2.1 or later, see COPYING for more details.

strace test suite is now provided under the terms of the GNU General
Public License version 2 or later, see tests/COPYING for more details.
2018-12-10 00:00:00 +00:00

312 lines
6.7 KiB
C

/*
* Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
* Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
* Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
* Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
* Copyright (c) 1999-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "defs.h"
#include <fcntl.h>
#include <sys/uio.h>
SYS_FUNC(read)
{
if (entering(tcp)) {
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
} else {
if (syserror(tcp))
printaddr(tcp->u_arg[1]);
else
printstrn(tcp, tcp->u_arg[1], tcp->u_rval);
tprintf(", %" PRI_klu, tcp->u_arg[2]);
}
return 0;
}
SYS_FUNC(write)
{
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
printstrn(tcp, tcp->u_arg[1], tcp->u_arg[2]);
tprintf(", %" PRI_klu, tcp->u_arg[2]);
return RVAL_DECODED;
}
struct print_iovec_config {
enum iov_decode decode_iov;
kernel_ulong_t data_size;
};
static bool
print_iovec(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
{
const kernel_ulong_t *iov;
kernel_ulong_t iov_buf[2], len;
struct print_iovec_config *c = data;
if (elem_size < sizeof(iov_buf)) {
iov_buf[0] = ((unsigned int *) elem_buf)[0];
iov_buf[1] = ((unsigned int *) elem_buf)[1];
iov = iov_buf;
} else {
iov = elem_buf;
}
tprints("{iov_base=");
len = iov[1];
switch (c->decode_iov) {
case IOV_DECODE_STR:
if (len > c->data_size)
len = c->data_size;
if (c->data_size != (kernel_ulong_t) -1)
c->data_size -= len;
printstrn(tcp, iov[0], len);
break;
case IOV_DECODE_NETLINK:
if (len > c->data_size)
len = c->data_size;
if (c->data_size != (kernel_ulong_t) -1)
c->data_size -= len;
/* assume that the descriptor is 1st syscall argument */
decode_netlink(tcp, tcp->u_arg[0], iov[0], len);
break;
default:
printaddr(iov[0]);
break;
}
tprintf(", iov_len=%" PRI_klu "}", iov[1]);
return true;
}
/*
* data_size limits the cumulative size of printed data.
* Example: recvmsg returing a short read.
*/
void
tprint_iov_upto(struct tcb *const tcp, const kernel_ulong_t len,
const kernel_ulong_t addr, const enum iov_decode decode_iov,
const kernel_ulong_t data_size)
{
kernel_ulong_t iov[2];
struct print_iovec_config config = {
.decode_iov = decode_iov, .data_size = data_size
};
print_array(tcp, addr, len, iov, current_wordsize * 2,
tfetch_mem_ignore_syserror, print_iovec, &config);
}
SYS_FUNC(readv)
{
if (entering(tcp)) {
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
} else {
tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1],
syserror(tcp) ? IOV_DECODE_ADDR :
IOV_DECODE_STR, tcp->u_rval);
tprintf(", %" PRI_klu, tcp->u_arg[2]);
}
return 0;
}
SYS_FUNC(writev)
{
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], IOV_DECODE_STR);
tprintf(", %" PRI_klu, tcp->u_arg[2]);
return RVAL_DECODED;
}
SYS_FUNC(pread)
{
if (entering(tcp)) {
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
} else {
if (syserror(tcp))
printaddr(tcp->u_arg[1]);
else
printstrn(tcp, tcp->u_arg[1], tcp->u_rval);
tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
printllval(tcp, "%lld", 3);
}
return 0;
}
SYS_FUNC(pwrite)
{
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
printstrn(tcp, tcp->u_arg[1], tcp->u_arg[2]);
tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
printllval(tcp, "%lld", 3);
return RVAL_DECODED;
}
static void
print_lld_from_low_high_val(struct tcb *tcp, int arg)
{
#if SIZEOF_KERNEL_LONG_T > 4
# ifndef current_klongsize
if (current_klongsize < SIZEOF_KERNEL_LONG_T) {
tprintf("%" PRI_kld, (tcp->u_arg[arg + 1] << 32)
| tcp->u_arg[arg]);
} else
# endif /* !current_klongsize */
{
tprintf("%" PRI_kld, tcp->u_arg[arg]);
}
#else /* SIZEOF_KERNEL_LONG_T == 4 */
tprintf("%lld",
((long long) tcp->u_arg[arg + 1] << 32)
| ((long long) tcp->u_arg[arg]));
#endif
}
#include "xlat/rwf_flags.h"
static int
do_preadv(struct tcb *tcp, const int flags_arg)
{
if (entering(tcp)) {
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
} else {
kernel_ulong_t len =
truncate_kulong_to_current_wordsize(tcp->u_arg[2]);
tprint_iov_upto(tcp, len, tcp->u_arg[1],
syserror(tcp) ? IOV_DECODE_ADDR :
IOV_DECODE_STR, tcp->u_rval);
tprintf(", %" PRI_klu ", ", len);
print_lld_from_low_high_val(tcp, 3);
if (flags_arg >= 0) {
tprints(", ");
printflags(rwf_flags, tcp->u_arg[flags_arg], "RWF_???");
}
}
return 0;
}
SYS_FUNC(preadv)
{
return do_preadv(tcp, -1);
}
static int
do_pwritev(struct tcb *tcp, const int flags_arg)
{
kernel_ulong_t len =
truncate_kulong_to_current_wordsize(tcp->u_arg[2]);
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
tprint_iov(tcp, len, tcp->u_arg[1], IOV_DECODE_STR);
tprintf(", %" PRI_klu ", ", len);
print_lld_from_low_high_val(tcp, 3);
if (flags_arg >= 0) {
tprints(", ");
printflags(rwf_flags, tcp->u_arg[flags_arg], "RWF_???");
}
return RVAL_DECODED;
}
SYS_FUNC(pwritev)
{
return do_pwritev(tcp, -1);
}
/*
* x32 is the only architecture where preadv2 takes 5 arguments
* instead of 6, see preadv64v2 in kernel sources.
* Likewise, x32 is the only architecture where pwritev2 takes 5 arguments
* instead of 6, see pwritev64v2 in kernel sources.
*/
#if defined X86_64
# define PREADV2_PWRITEV2_FLAGS_ARG_NO (current_personality == 2 ? 4 : 5)
#elif defined X32
# define PREADV2_PWRITEV2_FLAGS_ARG_NO (current_personality == 0 ? 4 : 5)
#else
# define PREADV2_PWRITEV2_FLAGS_ARG_NO 5
#endif
SYS_FUNC(preadv2)
{
return do_preadv(tcp, PREADV2_PWRITEV2_FLAGS_ARG_NO);
}
SYS_FUNC(pwritev2)
{
return do_pwritev(tcp, PREADV2_PWRITEV2_FLAGS_ARG_NO);
}
#include "xlat/splice_flags.h"
SYS_FUNC(tee)
{
/* int fd_in */
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
/* int fd_out */
printfd(tcp, tcp->u_arg[1]);
tprints(", ");
/* size_t len */
tprintf("%" PRI_klu ", ", tcp->u_arg[2]);
/* unsigned int flags */
printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???");
return RVAL_DECODED;
}
SYS_FUNC(splice)
{
/* int fd_in */
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
/* loff_t *off_in */
printnum_int64(tcp, tcp->u_arg[1], "%" PRId64);
tprints(", ");
/* int fd_out */
printfd(tcp, tcp->u_arg[2]);
tprints(", ");
/* loff_t *off_out */
printnum_int64(tcp, tcp->u_arg[3], "%" PRId64);
tprints(", ");
/* size_t len */
tprintf("%" PRI_klu ", ", tcp->u_arg[4]);
/* unsigned int flags */
printflags(splice_flags, tcp->u_arg[5], "SPLICE_F_???");
return RVAL_DECODED;
}
SYS_FUNC(vmsplice)
{
/* int fd */
printfd(tcp, tcp->u_arg[0]);
tprints(", ");
/* const struct iovec *iov, unsigned long nr_segs */
tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], IOV_DECODE_STR);
tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
/* unsigned int flags */
printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???");
return RVAL_DECODED;
}