X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=io.c;h=cd803057b32131931eab75decbcb7ae9809f2a61;hb=217eccfba5224fc47be2bd7b5b8b9b28b4fedf98;hp=5ee967c1bbee1cfd8e7e2540820a156d8cbb8fa3;hpb=c6e5e2c134b172ef531fd8382196993baf14bbc7;p=strace diff --git a/io.c b/io.c index 5ee967c1..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,70 +52,78 @@ 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; } -/* - * data_size limits the cumulative size of printed 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) +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) { - unsigned long iov[2]; - unsigned long size, cur, end, abbrev_end; - const unsigned long sizeof_iov = current_wordsize * 2; + const kernel_ulong_t *iov; + kernel_ulong_t iov_buf[2], len; + struct print_iovec_config *c = data; - if (!len) { - tprints("[]"); - return; - } - size = len * sizeof_iov; - end = addr + size; - if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)) || - !addr || size / sizeof_iov != len || end < addr) { - printaddr(addr); - return; - } - if (abbrev(tcp)) { - abbrev_end = addr + max_strlen * sizeof_iov; - if (abbrev_end < addr) - abbrev_end = end; + 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 { - abbrev_end = end; + iov = elem_buf; } - tprints("["); - for (cur = addr; cur < end; cur += sizeof_iov) { - if (cur > addr) - tprints(", "); - if (cur >= abbrev_end) { - tprints("..."); + + 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; - } - if (umove_ulong_array_or_printaddr(tcp, cur, iov, - ARRAY_SIZE(iov))) + 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; - tprints("{"); - if (decode_iov) { - unsigned long len = iov[1]; - if (len > data_size) - len = data_size; - data_size -= len; - printstr(tcp, iov[0], len); - } else + default: printaddr(iov[0]); - tprintf(", %lu}", iov[1]); + break; } - tprints("]"); + + 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(struct tcb *tcp, unsigned long len, unsigned long addr, int decode_iov) +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) { - tprint_iov_upto(tcp, len, addr, decode_iov, (unsigned long) -1L); + 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) @@ -123,8 +132,10 @@ SYS_FUNC(readv) printfd(tcp, tcp->u_arg[0]); tprints(", "); } else { - tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1); - 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, "%llu", 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,67 +170,112 @@ 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, "%llu", 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; } static void -print_llu_from_low_high_val(struct tcb *tcp, int arg) +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("%lu", (unsigned long) tcp->u_arg[arg]); -# if SUPPORTED_PERSONALITIES > 1 - else - tprintf("%lu", - ((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("%llu", (unsigned long long) tcp->ext_arg[arg]); - else -# endif - tprintf("%llu", - ((unsigned long long) (unsigned long) tcp->u_arg[arg + 1] << sizeof(long) * 8) - | (unsigned long long) (unsigned long) tcp->u_arg[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 } -SYS_FUNC(preadv) +#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 { - tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1); - tprintf(", %lu, ", tcp->u_arg[2]); - print_llu_from_low_high_val(tcp, 3); + 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(pwritev) +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, tcp->u_arg[2], tcp->u_arg[1], 1); - tprintf(", %lu, ", tcp->u_arg[2]); - print_llu_from_low_high_val(tcp, 3); + 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) @@ -242,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_???"); @@ -255,16 +300,16 @@ SYS_FUNC(splice) printfd(tcp, tcp->u_arg[0]); tprints(", "); /* loff_t *off_in */ - printnum_int64(tcp, tcp->u_arg[1], "%" PRIu64); + 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], "%" PRIu64); + 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_???"); @@ -277,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_???");