]> granicus.if.org Git - strace/blobdiff - dm.c
Remove linux/ptp_clock.h
[strace] / dm.c
diff --git a/dm.c b/dm.c
index 8f911e6d45a14b6a41b61f17d2d88a8ab1c191ea..28863a871df662b52c438a7dfc415c402306746f 100644 (file)
--- a/dm.c
+++ b/dm.c
@@ -1,24 +1,59 @@
+/*
+ * Support for decoding of DM_* ioctl commands.
+ *
+ * Copyright (c) 2016 Mikulas Patocka <mpatocka@redhat.com>
+ * Copyright (c) 2016 Masatake Yamato <yamato@redhat.com>
+ * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
+ * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * Copyright (c) 2016-2017 The strace developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include "defs.h"
 
 #ifdef HAVE_LINUX_DM_IOCTL_H
 
+# include "print_fields.h"
 # include <linux/dm-ioctl.h>
 # include <linux/ioctl.h>
 
-# include <sys/sysmacros.h>
-
 # if DM_VERSION_MAJOR == 4
 
 /* Definitions for command which have been added later */
 
 #  ifndef DM_LIST_VERSIONS
-#   define DM_LIST_VERSIONS    _IOWR(DM_IOCTL, 0xd, struct dm_ioctl)
+#   define DM_LIST_VERSIONS    _IOWR(DM_IOCTL, 0x0d, struct dm_ioctl)
 #  endif
 #  ifndef DM_TARGET_MSG
-#   define DM_TARGET_MSG       _IOWR(DM_IOCTL, 0xe, struct dm_ioctl)
+#   define DM_TARGET_MSG       _IOWR(DM_IOCTL, 0x0e, struct dm_ioctl)
 #  endif
 #  ifndef DM_DEV_SET_GEOMETRY
-#   define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, 0xf, struct dm_ioctl)
+#   define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, 0x0f, struct dm_ioctl)
+#  endif
+#  ifndef DM_DEV_ARM_POLL
+#   define DM_DEV_ARM_POLL     _IOWR(DM_IOCTL, 0x10, struct dm_ioctl)
 #  endif
 
 
@@ -32,18 +67,14 @@ dm_decode_device(const unsigned int code, const struct dm_ioctl *ioc)
                break;
        default:
                if (ioc->dev)
-                       tprintf(", dev=makedev(%u, %u)",
-                               major(ioc->dev), minor(ioc->dev));
-               if (ioc->name[0]) {
-                       tprints(", name=");
-                       print_quoted_string(ioc->name, DM_NAME_LEN,
-                                           QUOTE_0_TERMINATED);
-               }
-               if (ioc->uuid[0]) {
-                       tprints(", uuid=");
-                       print_quoted_string(ioc->uuid, DM_UUID_LEN,
-                                           QUOTE_0_TERMINATED);
-               }
+                       PRINT_FIELD_DEV(", ", *ioc, dev);
+
+               if (ioc->name[0])
+                       PRINT_FIELD_CSTRING(", ", *ioc, name);
+
+               if (ioc->uuid[0])
+                       PRINT_FIELD_CSTRING(", ", *ioc, uuid);
+
                break;
        }
 }
@@ -55,8 +86,7 @@ dm_decode_values(struct tcb *tcp, const unsigned int code,
        if (entering(tcp)) {
                switch (code) {
                case DM_TABLE_LOAD:
-                       tprintf(", target_count=%" PRIu32,
-                               ioc->target_count);
+                       PRINT_FIELD_U(", ", *ioc, target_count);
                        break;
                case DM_DEV_SUSPEND:
                        if (ioc->flags & DM_SUSPEND_FLAG)
@@ -65,8 +95,7 @@ dm_decode_values(struct tcb *tcp, const unsigned int code,
                case DM_DEV_RENAME:
                case DM_DEV_REMOVE:
                case DM_DEV_WAIT:
-                       tprintf(", event_nr=%" PRIu32,
-                               ioc->event_nr);
+                       PRINT_FIELD_U(", ", *ioc, event_nr);
                        break;
                }
        } else if (!syserror(tcp)) {
@@ -81,12 +110,9 @@ dm_decode_values(struct tcb *tcp, const unsigned int code,
                case DM_TABLE_DEPS:
                case DM_TABLE_STATUS:
                case DM_TARGET_MSG:
-                       tprintf(", target_count=%" PRIu32,
-                               ioc->target_count);
-                       tprintf(", open_count=%" PRIu32,
-                               ioc->open_count);
-                       tprintf(", event_nr=%" PRIu32,
-                               ioc->event_nr);
+                       PRINT_FIELD_U(", ", *ioc, target_count);
+                       PRINT_FIELD_U(", ", *ioc, open_count);
+                       PRINT_FIELD_U(", ", *ioc, event_nr);
                        break;
                }
        }
@@ -97,19 +123,18 @@ dm_decode_values(struct tcb *tcp, const unsigned int code,
 static void
 dm_decode_flags(const struct dm_ioctl *ioc)
 {
-       tprints(", flags=");
-       printflags(dm_flags, ioc->flags, "DM_???");
+       PRINT_FIELD_FLAGS(", ", *ioc, flags, dm_flags, "DM_???");
 }
 
 static void
-dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ureg_t addr,
+dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ulong_t addr,
                         const struct dm_ioctl *const ioc)
 {
        static const uint32_t target_spec_size =
                sizeof(struct dm_target_spec);
        uint32_t i;
        uint32_t offset = ioc->data_start;
-       uint32_t offset_end;
+       uint32_t offset_end = 0;
 
        if (abbrev(tcp)) {
                if (ioc->target_count)
@@ -119,51 +144,50 @@ dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ureg_t addr,
        }
 
        for (i = 0; i < ioc->target_count; i++) {
-               struct dm_target_spec s;
+               tprints(", ");
+
+               if (i && offset <= offset_end)
+                       goto misplaced;
 
                offset_end = offset + target_spec_size;
 
                if (offset_end <= offset || offset_end > ioc->data_size)
                        goto misplaced;
 
-               tprints(", ");
-
                if (i >= max_strlen) {
                        tprints("...");
                        break;
                }
 
+               struct dm_target_spec s;
+
                if (umove_or_printaddr(tcp, addr + offset, &s))
                        break;
 
-               tprintf("{sector_start=%" PRI__u64 ", length=%" PRI__u64,
-                       s.sector_start, s.length);
+               PRINT_FIELD_U("{", s, sector_start);
+               PRINT_FIELD_U(", ", s, length);
 
                if (exiting(tcp))
-                       tprintf(", status=%" PRId32, s.status);
+                       PRINT_FIELD_D(", ", s, status);
 
-               tprints(", target_type=");
-               print_quoted_string(s.target_type, DM_MAX_TYPE_NAME,
-                                   QUOTE_0_TERMINATED);
+               PRINT_FIELD_CSTRING(", ", s, target_type);
 
                tprints(", string=");
                printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
                             QUOTE_0_TERMINATED);
-               tprintf("}");
+               tprints("}");
 
                if (entering(tcp))
                        offset += s.next;
                else
                        offset = ioc->data_start + s.next;
-
-               if (offset <= offset_end)
-                       goto misplaced;
        }
 
        return;
 
 misplaced:
-       tprints(", /* misplaced struct dm_target_spec */ ...");
+       tprints("???");
+       tprints_comment("misplaced struct dm_target_spec");
 }
 
 bool
@@ -171,15 +195,25 @@ dm_print_dev(struct tcb *tcp, void *dev_ptr, size_t dev_size, void *dummy)
 {
        uint64_t *dev = (uint64_t *) dev_ptr;
 
-       tprintf("makedev(%u, %u)", major(*dev), minor(*dev));
+       print_dev_t(*dev);
 
        return 1;
 }
 
 static void
-dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ureg_t addr,
+dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ulong_t addr,
                         const struct dm_ioctl *const ioc)
 {
+       if (ioc->data_start == ioc->data_size)
+               return;
+
+       tprints(", ");
+
+       if (abbrev(tcp)) {
+               tprints("...");
+               return;
+       }
+
        static const uint32_t target_deps_dev_offs =
                offsetof(struct dm_target_deps, dev);
        uint64_t dev_buf;
@@ -188,13 +222,6 @@ dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ureg_t addr,
        uint32_t offset_end = offset + target_deps_dev_offs;
        uint32_t space;
 
-       if (abbrev(tcp)) {
-               tprints(", ...");
-               return;
-       }
-
-       tprints(", ");
-
        if (offset_end <= offset || offset_end > ioc->data_size)
                goto misplaced;
 
@@ -206,8 +233,9 @@ dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ureg_t addr,
        if (s.count > space)
                goto misplaced;
 
-       tprintf("{count=%u, deps=", s.count);
+       PRINT_FIELD_U("{", s, count);
 
+       tprints(", deps=");
        print_array(tcp, addr + offset_end, s.count, &dev_buf, sizeof(dev_buf),
                    umoven_or_printaddr, dm_print_dev, NULL);
 
@@ -216,33 +244,40 @@ dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ureg_t addr,
        return;
 
 misplaced:
-       tprints("/* misplaced struct dm_target_deps */ ...");
+       tprints("???");
+       tprints_comment("misplaced struct dm_target_deps");
 }
 
 static void
-dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ureg_t addr,
+dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
                       const struct dm_ioctl *const ioc)
 {
        static const uint32_t name_list_name_offs =
                offsetof(struct dm_name_list, name);
        struct dm_name_list s;
        uint32_t offset = ioc->data_start;
-       uint32_t offset_end;
+       uint32_t offset_end = 0;
        uint32_t count;
 
+       if (ioc->data_start == ioc->data_size)
+               return;
+
        if (abbrev(tcp)) {
                tprints(", ...");
                return;
        }
 
        for (count = 0;; count++) {
+               tprints(", ");
+
+               if (count && offset <= offset_end)
+                       goto misplaced;
+
                offset_end = offset + name_list_name_offs;
 
                if (offset_end <= offset || offset_end > ioc->data_size)
                        goto misplaced;
 
-               tprints(", ");
-
                if (count >= max_strlen) {
                        tprints("...");
                        break;
@@ -250,13 +285,9 @@ dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ureg_t addr,
 
                if (umove_or_printaddr(tcp, addr + offset, &s))
                        break;
-               if (!count && !s.dev) {
-                       tprints("/* no devices present */");
-                       break;
-               }
 
-               tprintf("{dev=makedev(%u, %u), name=", major(s.dev),
-                       minor(s.dev));
+               PRINT_FIELD_DEV("{", s, dev);
+               tprints(", name=");
                printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
                            QUOTE_0_TERMINATED);
                tprints("}");
@@ -265,40 +296,45 @@ dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ureg_t addr,
                        break;
 
                offset += s.next;
-               if (offset <= offset_end)
-                       goto misplaced;
        }
 
        return;
 
 misplaced:
-       tprints(", /* misplaced struct dm_name_list */ ...");
+       tprints("???");
+       tprints_comment("misplaced struct dm_name_list");
 }
 
 static void
-dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ureg_t addr,
+dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ulong_t addr,
                             const struct dm_ioctl *const ioc)
 {
        static const uint32_t target_vers_name_offs =
                offsetof(struct dm_target_versions, name);
        struct dm_target_versions s;
        uint32_t offset = ioc->data_start;
-       uint32_t offset_end;
+       uint32_t offset_end = 0;
        uint32_t count;
 
+       if (ioc->data_start == ioc->data_size)
+               return;
+
        if (abbrev(tcp)) {
                tprints(", ...");
                return;
        }
 
        for (count = 0;; count++) {
+               tprints(", ");
+
+               if (count && offset <= offset_end)
+                       goto misplaced;
+
                offset_end = offset + target_vers_name_offs;
 
                if (offset_end <= offset || offset_end > ioc->data_size)
                        goto misplaced;
 
-               tprints(", ");
-
                if (count >= max_strlen) {
                        tprints("...");
                        break;
@@ -317,64 +353,71 @@ dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ureg_t addr,
                        break;
 
                offset += s.next;
-               if (offset <= offset_end)
-                       goto misplaced;
        }
 
        return;
 
 misplaced:
-       tprints(", /* misplaced struct dm_target_versions */ ...");
+       tprints("???");
+       tprints_comment("misplaced struct dm_target_versions");
 }
 
 static void
-dm_decode_dm_target_msg(struct tcb *const tcp, const kernel_ureg_t addr,
-                       const struct dm_ioctl *const ioc)
+dm_decode_dm_target_msg(struct tcb *const tcp, const kernel_ulong_t addr,
+                       const struct dm_ioctl *const ioc)
 {
-       static const uint32_t target_msg_message_offs =
-               offsetof(struct dm_target_msg, message);
-       uint32_t offset = ioc->data_start;
-       uint32_t offset_end = offset + target_msg_message_offs;
+       if (ioc->data_start == ioc->data_size)
+               return;
+
+       tprints(", ");
 
        if (abbrev(tcp)) {
-               tprints("...");
+               tprints("...");
                return;
        }
 
+       static const uint32_t target_msg_message_offs =
+               offsetof(struct dm_target_msg, message);
+       uint32_t offset = ioc->data_start;
+       uint32_t offset_end = offset + target_msg_message_offs;
+
        if (offset_end > offset && offset_end <= ioc->data_size) {
                struct dm_target_msg s;
 
-               tprints(", ");
-
                if (umove_or_printaddr(tcp, addr + offset, &s))
                        return;
 
-               tprintf("{sector=%" PRI__u64 ", message=", s.sector);
+               PRINT_FIELD_U("{", s, sector);
+               tprints(", message=");
                printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
                            QUOTE_0_TERMINATED);
                tprints("}");
        } else {
-               tprints(", /* misplaced struct dm_target_msg */");
+               tprints("???");
+               tprints_comment("misplaced struct dm_target_msg");
        }
 }
 
 static void
-dm_decode_string(struct tcb *const tcp, const kernel_ureg_t addr,
+dm_decode_string(struct tcb *const tcp, const kernel_ulong_t addr,
                 const struct dm_ioctl *const ioc)
 {
-       uint32_t offset = ioc->data_start;
+       tprints(", ");
 
        if (abbrev(tcp)) {
-               tprints("...");
+               tprints("...");
                return;
        }
 
-       if (offset < ioc->data_size) {
-               tprints(", string=");
+       uint32_t offset = ioc->data_start;
+
+       if (offset <= ioc->data_size) {
+               tprints("string=");
                printstr_ex(tcp, addr + offset, ioc->data_size - offset,
                            QUOTE_0_TERMINATED);
        } else {
-               tprints(", /* misplaced string */");
+               tprints("???");
+               tprints_comment("misplaced string");
        }
 }
 
@@ -389,6 +432,7 @@ dm_ioctl_has_params(const unsigned int code)
        case DM_DEV_SUSPEND:
        case DM_DEV_STATUS:
        case DM_TABLE_CLEAR:
+       case DM_DEV_ARM_POLL:
                return false;
        }
 
@@ -396,7 +440,8 @@ dm_ioctl_has_params(const unsigned int code)
 }
 
 static int
-dm_known_ioctl(struct tcb *tcp, const unsigned int code, long arg)
+dm_known_ioctl(struct tcb *const tcp, const unsigned int code,
+              const kernel_ulong_t arg)
 {
        struct dm_ioctl *ioc = NULL;
        struct dm_ioctl *entering_ioc = NULL;
@@ -438,7 +483,7 @@ dm_known_ioctl(struct tcb *tcp, const unsigned int code, long arg)
        }
 
        if (exiting(tcp) && syserror(tcp) && !ioc_changed)
-               return 1;
+               return RVAL_IOCTL_DECODED;
 
        /*
         * device mapper code uses %d in some places and %u in another, but
@@ -451,20 +496,20 @@ dm_known_ioctl(struct tcb *tcp, const unsigned int code, long arg)
         * ioctl fields
         */
        if (ioc->version[0] != DM_VERSION_MAJOR) {
-               tprints(", /* Unsupported device mapper ABI version */ ...");
+               tprints_comment("unsupported device mapper ABI version");
                goto skip;
        }
 
-       tprintf(", data_size=%u", ioc->data_size);
-
-       if (dm_ioctl_has_params(code))
-               tprintf(", data_start=%u", ioc->data_start);
+       PRINT_FIELD_U(", ", *ioc, data_size);
 
        if (ioc->data_size < offsetof(struct dm_ioctl, data)) {
-               tprints(", /* Incorrect data_size */ ...");
+               tprints_comment("data_size too small");
                goto skip;
        }
 
+       if (dm_ioctl_has_params(code))
+               PRINT_FIELD_U(", ", *ioc, data_start);
+
        dm_decode_device(code, ioc);
        dm_decode_values(tcp, code, ioc);
        dm_decode_flags(ioc);
@@ -512,11 +557,11 @@ dm_known_ioctl(struct tcb *tcp, const unsigned int code, long arg)
 
  skip:
        tprints("}");
-       return 1;
+       return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
 }
 
 int
-dm_ioctl(struct tcb *tcp, const unsigned int code, long arg)
+dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
 {
        switch (code) {
        case DM_VERSION:
@@ -535,18 +580,19 @@ dm_ioctl(struct tcb *tcp, const unsigned int code, long arg)
        case DM_LIST_VERSIONS:
        case DM_TARGET_MSG:
        case DM_DEV_SET_GEOMETRY:
+       case DM_DEV_ARM_POLL:
                return dm_known_ioctl(tcp, code, arg);
        default:
-               return 0;
+               return RVAL_DECODED;
        }
 }
 
 # else /* !(DM_VERSION_MAJOR == 4) */
 
 int
-dm_ioctl(struct tcb *tcp, const unsigned int code, long arg)
+dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
 {
-       return 0;
+       return RVAL_DECODED;
 }
 
 # endif /* DM_VERSION_MAJOR == 4 */