X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=io.c;h=cd803057b32131931eab75decbcb7ae9809f2a61;hb=217eccfba5224fc47be2bd7b5b8b9b28b4fedf98;hp=3c4ef592f1d376c3f176ad8a8cbbf778040c7083;hpb=a6dd09428707bfb87e27abcb0c8f7066e2eaf988;p=strace diff --git a/io.c b/io.c index 3c4ef592..cd803057 100644 --- a/io.c +++ b/io.c @@ -3,6 +3,7 @@ * Copyright (c) 1993 Branko Lankester * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey * Copyright (c) 1996-1999 Wichert Akkerman + * Copyright (c) 1999-2018 The strace developers. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,8 +42,8 @@ SYS_FUNC(read) if (syserror(tcp)) printaddr(tcp->u_arg[1]); else - printstr(tcp, tcp->u_arg[1], tcp->u_rval); - tprintf(", %lu", tcp->u_arg[2]); + printstrn(tcp, tcp->u_arg[1], tcp->u_rval); + tprintf(", %" PRI_klu, tcp->u_arg[2]); } return 0; } @@ -51,25 +52,25 @@ SYS_FUNC(write) { printfd(tcp, tcp->u_arg[0]); tprints(", "); - printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); - tprintf(", %lu", tcp->u_arg[2]); + printstrn(tcp, tcp->u_arg[1], tcp->u_arg[2]); + tprintf(", %" PRI_klu, tcp->u_arg[2]); return RVAL_DECODED; } struct print_iovec_config { - int decode_iov; - unsigned long data_size; + 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 unsigned long *iov; - unsigned long iov_buf[2]; + const kernel_ulong_t *iov; + kernel_ulong_t iov_buf[2], len; struct print_iovec_config *c = data; - if (elem_size < sizeof(iov_buf)) { + 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; @@ -77,19 +78,32 @@ print_iovec(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data) iov = elem_buf; } - tprints("{"); - - if (c->decode_iov) { - unsigned long len = iov[1]; - if (len > c->data_size) - len = c->data_size; - c->data_size -= len; - printstr(tcp, iov[0], len); - } else { - printaddr(iov[0]); + 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(", %lu}", iov[1]); + tprintf(", iov_len=%" PRI_klu "}", iov[1]); return true; } @@ -99,21 +113,17 @@ print_iovec(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data) * Example: recvmsg returing a short read. */ void -tprint_iov_upto(struct tcb *tcp, unsigned long len, unsigned long addr, - int decode_iov, unsigned long data_size) +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) { - unsigned long iov[2]; - struct print_iovec_config config = - { .decode_iov = decode_iov, .data_size = 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, - umoven_or_printaddr, print_iovec, &config); -} - -void -tprint_iov(struct tcb *tcp, unsigned long len, unsigned long addr, int decode_iov) -{ - tprint_iov_upto(tcp, len, addr, decode_iov, (unsigned long) -1L); + tfetch_mem_ignore_syserror, print_iovec, &config); } SYS_FUNC(readv) @@ -122,9 +132,10 @@ SYS_FUNC(readv) printfd(tcp, tcp->u_arg[0]); tprints(", "); } else { - tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], 1, - tcp->u_rval); - tprintf(", %lu", tcp->u_arg[2]); + 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; } @@ -133,23 +144,12 @@ SYS_FUNC(writev) { printfd(tcp, tcp->u_arg[0]); tprints(", "); - tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1); - tprintf(", %lu", tcp->u_arg[2]); + tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], IOV_DECODE_STR); + tprintf(", %" PRI_klu, tcp->u_arg[2]); return RVAL_DECODED; } -/* The SH4 ABI does allow long longs in odd-numbered registers, but - does not allow them to be split between registers and memory - and - there are only four argument registers for normal functions. As a - result pread takes an extra padding argument before the offset. This - was changed late in the 2.4 series (around 2.4.20). */ -#if defined(SH) -#define PREAD_OFFSET_ARG 4 -#else -#define PREAD_OFFSET_ARG 3 -#endif - SYS_FUNC(pread) { if (entering(tcp)) { @@ -159,9 +159,9 @@ SYS_FUNC(pread) if (syserror(tcp)) printaddr(tcp->u_arg[1]); else - printstr(tcp, tcp->u_arg[1], tcp->u_rval); - tprintf(", %lu, ", tcp->u_arg[2]); - printllval(tcp, "%lld", PREAD_OFFSET_ARG); + printstrn(tcp, tcp->u_arg[1], tcp->u_rval); + tprintf(", %" PRI_klu ", ", tcp->u_arg[2]); + printllval(tcp, "%lld", 3); } return 0; } @@ -170,9 +170,9 @@ SYS_FUNC(pwrite) { printfd(tcp, tcp->u_arg[0]); tprints(", "); - printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); - tprintf(", %lu, ", tcp->u_arg[2]); - printllval(tcp, "%lld", PREAD_OFFSET_ARG); + printstrn(tcp, tcp->u_arg[1], tcp->u_arg[2]); + tprintf(", %" PRI_klu ", ", tcp->u_arg[2]); + printllval(tcp, "%lld", 3); return RVAL_DECODED; } @@ -180,30 +180,20 @@ SYS_FUNC(pwrite) static void print_lld_from_low_high_val(struct tcb *tcp, int arg) { -#if SIZEOF_LONG == SIZEOF_LONG_LONG -# if SUPPORTED_PERSONALITIES > 1 -# ifdef X86_64 - if (current_personality != 1) -# else - if (current_wordsize == sizeof(long)) -# endif -# endif - tprintf("%ld", tcp->u_arg[arg]); -# if SUPPORTED_PERSONALITIES > 1 - else - tprintf("%ld", - ((unsigned long) tcp->u_arg[arg + 1] << current_wordsize * 8) - | (unsigned long) tcp->u_arg[arg]); -# endif -#else -# ifdef X32 - if (current_personality == 0) - tprintf("%lld", tcp->ext_arg[arg]); - else -# endif +#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", - ((unsigned long long) (unsigned long) tcp->u_arg[arg + 1] << sizeof(long) * 8) - | (unsigned long long) (unsigned long) tcp->u_arg[arg]); + ((long long) tcp->u_arg[arg + 1] << 32) + | ((long long) tcp->u_arg[arg])); #endif } @@ -216,9 +206,13 @@ do_preadv(struct tcb *tcp, const int flags_arg) printfd(tcp, tcp->u_arg[0]); tprints(", "); } else { - tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], 1, - tcp->u_rval); - tprintf(", %lu, ", tcp->u_arg[2]); + 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(", "); @@ -233,18 +227,16 @@ SYS_FUNC(preadv) return do_preadv(tcp, -1); } -SYS_FUNC(preadv2) -{ - return do_preadv(tcp, 5); -} - 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, tcp->u_arg[2], tcp->u_arg[1], 1); - tprintf(", %lu, ", tcp->u_arg[2]); + 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(", "); @@ -259,9 +251,29 @@ 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, 5); + return do_pwritev(tcp, PREADV2_PWRITEV2_FLAGS_ARG_NO); } #include "xlat/splice_flags.h" @@ -275,7 +287,7 @@ SYS_FUNC(tee) printfd(tcp, tcp->u_arg[1]); tprints(", "); /* size_t len */ - tprintf("%lu, ", tcp->u_arg[2]); + tprintf("%" PRI_klu ", ", tcp->u_arg[2]); /* unsigned int flags */ printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???"); @@ -297,7 +309,7 @@ SYS_FUNC(splice) printnum_int64(tcp, tcp->u_arg[3], "%" PRId64); tprints(", "); /* size_t len */ - tprintf("%lu, ", tcp->u_arg[4]); + tprintf("%" PRI_klu ", ", tcp->u_arg[4]); /* unsigned int flags */ printflags(splice_flags, tcp->u_arg[5], "SPLICE_F_???"); @@ -310,8 +322,8 @@ SYS_FUNC(vmsplice) 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], 1); - tprintf(", %lu, ", tcp->u_arg[2]); + 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_???");