]> granicus.if.org Git - strace/blobdiff - io.c
Print struct iovec as a regular structure
[strace] / io.c
diff --git a/io.c b/io.c
index cda5f92c2589838d8806d5e299e0966b1d414f1a..58323a7c708435bb005b9c1972ed646b66db01e3 100644 (file)
--- a/io.c
+++ b/io.c
@@ -57,69 +57,72 @@ SYS_FUNC(write)
        return RVAL_DECODED;
 }
 
+struct print_iovec_config {
+       enum iov_decode decode_iov;
+       unsigned long 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], 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;
+                       c->data_size -= len;
+                       printstr(tcp, iov[0], len);
+                       break;
+               case IOV_DECODE_NETLINK:
+                       if (len > c->data_size)
+                               len = c->data_size;
+                       c->data_size -= len;
+                       decode_netlink(tcp, iov[0], iov[1]);
+                       break;
+               default:
+                       printaddr(iov[0]);
+                       break;
+       }
+
+       tprintf(", iov_len=%lu}", 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 *tcp, unsigned long len, unsigned long addr, int decode_iov, unsigned long data_size)
+tprint_iov_upto(struct tcb *tcp, unsigned long len, unsigned long addr,
+               enum iov_decode decode_iov, unsigned long data_size)
 {
        unsigned long iov[2];
-       unsigned long size, cur, end, abbrev_end;
-       const unsigned long sizeof_iov = current_wordsize * 2;
+       struct print_iovec_config config =
+               { .decode_iov = decode_iov, .data_size = data_size };
 
-       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;
-       } else {
-               abbrev_end = end;
-       }
-       if (addr >= abbrev_end) {
-               tprints("[...]");
-               return;
-       }
-       for (cur = addr; cur < end; cur += sizeof_iov) {
-               if (cur > addr) {
-                       tprints(", ");
-                       if (cur >= abbrev_end) {
-                               tprints("...");
-                               break;
-                       }
-               }
-               if (umove_ulong_array_or_printaddr(tcp, cur, iov,
-                                                  ARRAY_SIZE(iov)))
-                       break;
-               if (cur <= addr)
-                       tprints("[");
-               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
-                       printaddr(iov[0]);
-               tprintf(", %lu}", iov[1]);
-       }
-       if (cur > addr)
-               tprints("]");
+       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(struct tcb *tcp, unsigned long len, unsigned long addr,
+          enum iov_decode decode_iov)
 {
        tprint_iov_upto(tcp, len, addr, decode_iov, (unsigned long) -1L);
 }
@@ -130,8 +133,8 @@ 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);
+               tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1],
+                               IOV_DECODE_STR, tcp->u_rval);
                tprintf(", %lu", tcp->u_arg[2]);
        }
        return 0;
@@ -141,7 +144,7 @@ SYS_FUNC(writev)
 {
        printfd(tcp, tcp->u_arg[0]);
        tprints(", ");
-       tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
+       tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], IOV_DECODE_STR);
        tprintf(", %lu", tcp->u_arg[2]);
 
        return RVAL_DECODED;
@@ -169,7 +172,7 @@ SYS_FUNC(pread)
                else
                        printstr(tcp, tcp->u_arg[1], tcp->u_rval);
                tprintf(", %lu, ", tcp->u_arg[2]);
-               printllval(tcp, "%llu", PREAD_OFFSET_ARG);
+               printllval(tcp, "%lld", PREAD_OFFSET_ARG);
        }
        return 0;
 }
@@ -180,7 +183,7 @@ SYS_FUNC(pwrite)
        tprints(", ");
        printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
        tprintf(", %lu, ", tcp->u_arg[2]);
-       printllval(tcp, "%llu", PREAD_OFFSET_ARG);
+       printllval(tcp, "%lld", PREAD_OFFSET_ARG);
 
        return RVAL_DECODED;
 }
@@ -188,7 +191,7 @@ SYS_FUNC(pwrite)
 static void
 print_lld_from_low_high_val(struct tcb *tcp, int arg)
 {
-#if SIZEOF_LONG == SIZEOF_LONG_LONG
+#if SIZEOF_LONG > 4 && SIZEOF_LONG == SIZEOF_LONG_LONG
 # if SUPPORTED_PERSONALITIES > 1
 #  ifdef X86_64
        if (current_personality != 1)
@@ -203,42 +206,83 @@ print_lld_from_low_high_val(struct tcb *tcp, int arg)
                        ((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
+#elif SIZEOF_LONG > 4
+# error Unsupported configuration: SIZEOF_LONG > 4 && SIZEOF_LONG_LONG > SIZEOF_LONG
+#elif HAVE_STRUCT_TCB_EXT_ARG
+# if SUPPORTED_PERSONALITIES > 1
+       if (current_personality == 1) {
+               tprintf("%lld",
+                       (widen_to_ull(tcp->u_arg[arg + 1]) << sizeof(long) * 8)
+                       | widen_to_ull(tcp->u_arg[arg]));
+       } else
 # endif
+       {
+               tprintf("%lld", tcp->ext_arg[arg]);
+       }
+#else /* SIZEOF_LONG_LONG > SIZEOF_LONG && !HAVE_STRUCT_TCB_EXT_ARG */
        tprintf("%lld",
-               ((unsigned long long) (unsigned long) tcp->u_arg[arg + 1] << sizeof(long) * 8)
-               | (unsigned long long) (unsigned long) tcp->u_arg[arg]);
+               (widen_to_ull(tcp->u_arg[arg + 1]) << sizeof(long) * 8)
+               | widen_to_ull(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);
+               tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], IOV_DECODE_STR,
+                               tcp->u_rval);
                tprintf(", %lu, ", tcp->u_arg[2]);
                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);
+}
+
+SYS_FUNC(preadv2)
+{
+       return do_preadv(tcp, 5);
+}
+
+static int
+do_pwritev(struct tcb *tcp, const int flags_arg)
 {
        printfd(tcp, tcp->u_arg[0]);
        tprints(", ");
-       tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
+       tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], IOV_DECODE_STR);
        tprintf(", %lu, ", tcp->u_arg[2]);
        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);
+}
+
+SYS_FUNC(pwritev2)
+{
+       return do_pwritev(tcp, 5);
+}
+
 #include "xlat/splice_flags.h"
 
 SYS_FUNC(tee)
@@ -285,7 +329,7 @@ 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);
+       tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], IOV_DECODE_STR);
        tprintf(", %lu, ", tcp->u_arg[2]);
        /* unsigned int flags */
        printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???");