]> granicus.if.org Git - strace/blobdiff - mmsghdr.c
nlattr: add UID/GID netlink attribute decoders
[strace] / mmsghdr.c
index 8501f4a50b06c96ce4e5b6114f88dd9c20a0cff2..23e616a3a8d3bd31a5e5eaa69793ec7549e0471c 100644 (file)
--- a/mmsghdr.c
+++ b/mmsghdr.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2012-2013 Denys Vlasenko <vda.linux@googlemail.com>
  * Copyright (c) 2014 Masatake YAMATO <yamato@redhat.com>
  * Copyright (c) 2010-2016 Dmitry V. Levin <ldv@altlinux.org>
+ * Copyright (c) 2016-2018 The strace developers.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #include "defs.h"
 #include "msghdr.h"
+#include "xstring.h"
+#include <limits.h>
 
-static int
-decode_mmsghdr(struct tcb *tcp, const int *const p_user_msg_namelen,
-              const long addr, const bool use_msg_len)
+static bool
+fetch_struct_mmsghdr_for_print(struct tcb *const tcp,
+                                 const kernel_ulong_t addr,
+                                 const unsigned int len, void *const mh)
 {
-       struct mmsghdr mmsg;
-       int fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg);
+       return (entering(tcp) || !syserror(tcp)) &&
+              fetch_struct_mmsghdr(tcp, addr, mh);
+}
 
-       if (fetched) {
-               tprints("{msg_hdr=");
-               print_struct_msghdr(tcp, &mmsg.msg_hdr, p_user_msg_namelen,
-                                   use_msg_len ? mmsg.msg_len : -1UL);
-               tprintf(", msg_len=%u}", mmsg.msg_len);
-       } else {
-               printaddr(addr);
+struct print_struct_mmsghdr_config {
+       const int *p_user_msg_namelen;
+       unsigned int msg_len_vlen;
+       unsigned int count;
+       bool use_msg_len;
+};
+
+static bool
+print_struct_mmsghdr(struct tcb *tcp, void *elem_buf,
+                    size_t elem_size, void *data)
+{
+       const struct mmsghdr *const mmsg = elem_buf;
+       struct print_struct_mmsghdr_config *const c = data;
+
+       if (!c->count) {
+               tprints("...");
+               return false;
+       }
+       --c->count;
+
+       tprints("{msg_hdr=");
+       print_struct_msghdr(tcp, &mmsg->msg_hdr, c->p_user_msg_namelen,
+                           c->use_msg_len ? mmsg->msg_len : (kernel_ulong_t) -1);
+       if (c->msg_len_vlen) {
+               tprintf(", msg_len=%u", mmsg->msg_len);
+               --c->msg_len_vlen;
        }
+       tprints("}");
+
+       if (c->p_user_msg_namelen)
+               ++c->p_user_msg_namelen;
 
-       return fetched;
+       return true;
 }
 
 static void
-decode_mmsgvec(struct tcb *tcp, unsigned long addr, unsigned int len,
-              bool use_msg_len)
+free_mmsgvec_data(void *ptr)
 {
-       if (syserror(tcp)) {
-               printaddr(addr);
-       } else {
-               unsigned int i, fetched;
-
-               tprints("[");
-               for (i = 0; i < len; ++i, addr += fetched) {
-                       if (i)
-                               tprints(", ");
-                       fetched = decode_mmsghdr(tcp, 0, addr, use_msg_len);
-                       if (!fetched)
-                               break;
-               }
-               tprints("]");
+       char **pstr = ptr;
+       free(*pstr);
+       *pstr = 0;
+
+       free(ptr);
+}
+
+struct mmsgvec_data {
+       char *timeout;
+       unsigned int count;
+       int namelen[IOV_MAX];
+};
+
+static void
+save_mmsgvec_namelen(struct tcb *const tcp, kernel_ulong_t addr,
+                    unsigned int len, const char *const timeout)
+{
+       if (len > IOV_MAX)
+               len = IOV_MAX;
+
+       const size_t data_size = offsetof(struct mmsgvec_data, namelen)
+                                + sizeof(int) * len;
+       struct mmsgvec_data *const data = xmalloc(data_size);
+       data->timeout = xstrdup(timeout);
+
+       unsigned int i, fetched;
+
+       for (i = 0; i < len; ++i, addr += fetched) {
+               struct mmsghdr mh;
+
+               fetched = fetch_struct_mmsghdr(tcp, addr, &mh);
+               if (!fetched)
+                       break;
+               data->namelen[i] = mh.msg_hdr.msg_namelen;
        }
+       data->count = i;
+
+       set_tcb_priv_data(tcp, data, free_mmsgvec_data);
+}
+
+static void
+decode_mmsgvec(struct tcb *const tcp, const kernel_ulong_t addr,
+              const unsigned int vlen, const unsigned int msg_len_vlen,
+              const bool use_msg_len)
+{
+       struct mmsghdr mmsg;
+       struct print_struct_mmsghdr_config c = {
+               .msg_len_vlen = msg_len_vlen,
+               .count = IOV_MAX,
+               .use_msg_len = use_msg_len
+       };
+       const struct mmsgvec_data *const data = get_tcb_priv_data(tcp);
+
+       if (data) {
+               if (data->count < c.count)
+                       c.count = data->count;
+               c.p_user_msg_namelen = data->namelen;
+       }
+
+       print_array(tcp, addr, vlen, &mmsg, sizeof_struct_mmsghdr(),
+                   fetch_struct_mmsghdr_for_print,
+                   print_struct_mmsghdr, &c);
 }
 
 void
-dumpiov_in_mmsghdr(struct tcb *tcp, long addr)
+dumpiov_in_mmsghdr(struct tcb *const tcp, kernel_ulong_t addr)
 {
        unsigned int len = tcp->u_rval;
        unsigned int i, fetched;
@@ -82,10 +156,11 @@ dumpiov_in_mmsghdr(struct tcb *tcp, long addr)
                fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg);
                if (!fetched)
                        break;
-               tprintf(" = %lu buffers in vector %u\n",
-                       (unsigned long) mmsg.msg_hdr.msg_iovlen, i);
+               tprintf(" = %" PRI_klu " buffers in vector %u\n",
+                       (kernel_ulong_t) mmsg.msg_hdr.msg_iovlen, i);
                dumpiov_upto(tcp, mmsg.msg_hdr.msg_iovlen,
-                       (long) mmsg.msg_hdr.msg_iov, mmsg.msg_len);
+                            ptr_to_kulong(mmsg.msg_hdr.msg_iov),
+                            mmsg.msg_len);
        }
 }
 
@@ -96,6 +171,7 @@ SYS_FUNC(sendmmsg)
                printfd(tcp, tcp->u_arg[0]);
                tprints(", ");
                if (!verbose(tcp)) {
+                       /* msgvec */
                        printaddr(tcp->u_arg[1]);
                        /* vlen */
                        tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
@@ -104,7 +180,13 @@ SYS_FUNC(sendmmsg)
                        return RVAL_DECODED;
                }
        } else {
-               decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval, false);
+               const unsigned int msg_len_vlen =
+                       syserror(tcp) ? 0 : tcp->u_rval;
+               /* msgvec */
+               temporarily_clear_syserror(tcp);
+               decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_arg[2],
+                              msg_len_vlen, false);
+               restore_cleared_syserror(tcp);
                /* vlen */
                tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
                /* flags */
@@ -115,17 +197,14 @@ SYS_FUNC(sendmmsg)
 
 SYS_FUNC(recvmmsg)
 {
-       static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
-
        if (entering(tcp)) {
                printfd(tcp, tcp->u_arg[0]);
                tprints(", ");
                if (verbose(tcp)) {
-                       /* Abusing tcp->auxstr as temp storage.
-                        * Will be used and cleared on syscall exit.
-                        */
-                       tcp->auxstr = sprint_timespec(tcp, tcp->u_arg[4]);
+                       save_mmsgvec_namelen(tcp, tcp->u_arg[1], tcp->u_arg[2],
+                                            sprint_timespec(tcp, tcp->u_arg[4]));
                } else {
+                       /* msgvec */
                        printaddr(tcp->u_arg[1]);
                        /* vlen */
                        tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
@@ -137,15 +216,16 @@ SYS_FUNC(recvmmsg)
                return 0;
        } else {
                if (verbose(tcp)) {
-                       decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval, true);
+                       /* msgvec */
+                       decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval,
+                                      tcp->u_rval, true);
                        /* vlen */
                        tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
                        /* flags */
                        printflags(msg_flags, tcp->u_arg[3], "MSG_???");
                        tprints(", ");
                        /* timeout on entrance */
-                       tprints(tcp->auxstr);
-                       tcp->auxstr = NULL;
+                       tprints(*(const char **) get_tcb_priv_data(tcp));
                }
                if (syserror(tcp))
                        return 0;
@@ -153,11 +233,11 @@ SYS_FUNC(recvmmsg)
                        tcp->auxstr = "Timeout";
                        return RVAL_STR;
                }
-               if (!verbose(tcp))
+               if (!verbose(tcp) || !tcp->u_arg[4])
                        return 0;
                /* timeout on exit */
-               snprintf(str, sizeof(str), "left %s",
-                        sprint_timespec(tcp, tcp->u_arg[4]));
+               static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
+               xsprintf(str, "left %s", sprint_timespec(tcp, tcp->u_arg[4]));
                tcp->auxstr = str;
                return RVAL_STR;
        }