+/*
+ * 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)
+{
+#if SUPPORTED_PERSONALITIES > 1
+ union {
+ struct { u_int32_t base; u_int32_t len; } iov32;
+ struct { u_int64_t base; u_int64_t len; } iov64;
+ } iov;
+#define sizeof_iov \
+ (current_wordsize == 4 ? sizeof(iov.iov32) : sizeof(iov.iov64))
+#define iov_iov_base \
+ (current_wordsize == 4 ? (uint64_t) iov.iov32.base : iov.iov64.base)
+#define iov_iov_len \
+ (current_wordsize == 4 ? (uint64_t) iov.iov32.len : iov.iov64.len)
+#else
+ struct iovec iov;
+#define sizeof_iov sizeof(iov)
+#define iov_iov_base iov.iov_base
+#define iov_iov_len iov.iov_len
+#endif
+ unsigned long size, cur, end, abbrev_end;
+ int failed = 0;
+
+ if (!len) {
+ tprints("[]");
+ return;
+ }
+ size = len * sizeof_iov;
+ end = addr + size;
+ if (!verbose(tcp) || size / sizeof_iov != len || end < addr) {
+ tprintf("%#lx", addr);
+ return;
+ }
+ if (abbrev(tcp)) {
+ abbrev_end = addr + max_strlen * sizeof_iov;
+ if (abbrev_end < addr)
+ abbrev_end = end;
+ } else {
+ abbrev_end = end;
+ }
+ tprints("[");
+ for (cur = addr; cur < end; cur += sizeof_iov) {
+ if (cur > addr)
+ tprints(", ");
+ if (cur >= abbrev_end) {
+ tprints("...");
+ break;
+ }
+ if (umoven(tcp, cur, sizeof_iov, (char *) &iov) < 0) {
+ tprints("?");
+ failed = 1;
+ break;
+ }
+ tprints("{");
+ if (decode_iov) {
+ unsigned long len = iov_iov_len;
+ if (len > data_size)
+ len = data_size;
+ data_size -= len;
+ printstr(tcp, (long) iov_iov_base, len);
+ } else
+ tprintf("%#lx", (long) iov_iov_base);
+ tprintf(", %lu}", (unsigned long)iov_iov_len);
+ }
+ tprints("]");
+ if (failed)
+ tprintf(" %#lx", addr);
+#undef sizeof_iov
+#undef iov_iov_base
+#undef iov_iov_len
+}
+
+void
+tprint_iov(struct tcb *tcp, unsigned long len, unsigned long addr, int decode_iov)