]> granicus.if.org Git - strace/blobdiff - mtd.c
travis: add build environment information to the travis log
[strace] / mtd.c
diff --git a/mtd.c b/mtd.c
index 9a16ad736061a144cb50d6453ed8ca92e733f1fa..b0468595a5167e97bf298a62a3c24ed2208ad063 100644 (file)
--- a/mtd.c
+++ b/mtd.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012 Mike Frysinger <vapier@gentoo.org>
+ * Copyright (c) 2012-2017 The strace developers.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,7 +27,9 @@
 
 #include "defs.h"
 
-#include <sys/ioctl.h>
+#include DEF_MPERS_TYPE(struct_mtd_oob_buf)
+
+#include <linux/ioctl.h>
 
 /* The mtd api changes quickly, so we have to keep a local copy */
 #include <linux/version.h>
 #else
 # include <mtd/mtd-abi.h>
 #endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
-# include "ubi-user.h"
-#else
-# include <mtd/ubi-user.h>
-#endif
 
-static const struct xlat mtd_mode_options[] = {
-       { MTD_OPS_PLACE_OOB,    "MTD_OPS_PLACE_OOB"     },
-       { MTD_OPS_AUTO_OOB,     "MTD_OPS_AUTO_OOB"      },
-       { MTD_OPS_RAW,          "MTD_OPS_RAW"           },
-       { 0,                    NULL                    },
-};
-
-static const struct xlat mtd_type_options[] = {
-       { MTD_ABSENT,           "MTD_ABSENT"            },
-       { MTD_RAM,              "MTD_RAM"               },
-       { MTD_ROM,              "MTD_ROM"               },
-       { MTD_NORFLASH,         "MTD_NORFLASH"          },
-       { MTD_NANDFLASH,        "MTD_NANDFLASH"         },
-       { MTD_DATAFLASH,        "MTD_DATAFLASH"         },
-       { MTD_UBIVOLUME,        "MTD_UBIVOLUME"         },
-       { MTD_MLCNANDFLASH,     "MTD_MLCNANDFLASH"      },
-       { 0,                    NULL                    },
-};
-
-static const struct xlat mtd_flags_options[] = {
-       { MTD_WRITEABLE,        "MTD_WRITEABLE"         },
-       { MTD_BIT_WRITEABLE,    "MTD_BIT_WRITEABLE"     },
-       { MTD_NO_ERASE,         "MTD_NO_ERASE"          },
-       { MTD_POWERUP_LOCK,     "MTD_POWERUP_LOCK"      },
-       { 0,                    NULL                    },
-};
-
-static const struct xlat mtd_otp_options[] = {
-       { MTD_OTP_OFF,          "MTD_OTP_OFF"           },
-       { MTD_OTP_FACTORY,      "MTD_OTP_FACTORY"       },
-       { MTD_OTP_USER,         "MTD_OTP_USER"          },
-       { 0,                    NULL                    },
-};
-
-static const struct xlat mtd_nandecc_options[] = {
-       { MTD_NANDECC_OFF,              "MTD_NANDECC_OFF"               },
-       { MTD_NANDECC_PLACE,            "MTD_NANDECC_PLACE"             },
-       { MTD_NANDECC_AUTOPLACE,        "MTD_NANDECC_AUTOPLACE"         },
-       { MTD_NANDECC_PLACEONLY,        "MTD_NANDECC_PLACEONLY"         },
-       { MTD_NANDECC_AUTOPL_USR,       "MTD_NANDECC_AUTOPL_USR"        },
-       { 0,                            NULL                            },
-};
-
-int mtd_ioctl(struct tcb *tcp, long code, long arg)
+typedef struct mtd_oob_buf struct_mtd_oob_buf;
+
+#include MPERS_DEFS
+
+#include "xlat/mtd_mode_options.h"
+#include "xlat/mtd_file_mode_options.h"
+#include "xlat/mtd_type_options.h"
+#include "xlat/mtd_flags_options.h"
+#include "xlat/mtd_otp_options.h"
+#include "xlat/mtd_nandecc_options.h"
+
+static void
+decode_erase_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
 {
-       struct mtd_info_user minfo;
        struct erase_info_user einfo;
-       struct erase_info_user64 einfo64;
-       struct mtd_oob_buf mbuf;
-       struct mtd_oob_buf64 mbuf64;
-       struct region_info_user rinfo;
-       struct otp_info oinfo;
-       struct mtd_ecc_stats estat;
-       struct mtd_write_req mreq;
-       struct nand_oobinfo ninfo;
-       struct nand_ecclayout_user nlay;
-       int i, j;
 
-       if (entering(tcp))
-               return 0;
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &einfo))
+               return;
 
-       switch (code) {
+       tprintf("{start=%#x, length=%#x}", einfo.start, einfo.length);
+}
 
-       case MEMGETINFO:
-               if (!verbose(tcp) || umove(tcp, arg, &minfo) < 0)
-                       return 0;
+static void
+decode_erase_info_user64(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct erase_info_user64 einfo64;
 
-               tprints(", {type=");
-               printxval(mtd_type_options, minfo.type, "MTD_???");
-               tprints(", flags=");
-               printflags(mtd_flags_options, minfo.flags, "MTD_???");
-               tprintf(", size=%#" PRIx32 ", erasesize=%#" PRIx32,
-                       minfo.size, minfo.erasesize);
-               tprintf(", writesize=%#" PRIx32 ", oobsize=%#" PRIx32,
-                       minfo.writesize, minfo.oobsize);
-               tprintf(", padding=%#" PRIx64 "}",
-                       (uint64_t) minfo.padding);
-               return 1;
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &einfo64))
+               return;
 
-       case MEMERASE:
-       case MEMLOCK:
-       case MEMUNLOCK:
-       case MEMISLOCKED:
-               if (!verbose(tcp) || umove(tcp, arg, &einfo) < 0)
-                       return 0;
+       tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}",
+               (uint64_t) einfo64.start, (uint64_t) einfo64.length);
+}
 
-               tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 "}",
-                       einfo.start, einfo.length);
-               return 1;
+static void
+decode_mtd_oob_buf(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct_mtd_oob_buf mbuf;
 
-       case MEMERASE64:
-               if (!verbose(tcp) || umove(tcp, arg, &einfo64) < 0)
-                       return 0;
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &mbuf))
+               return;
 
-               tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 "}",
-                       (uint64_t) einfo64.start, (uint64_t) einfo64.length);
-               return 1;
+       tprintf("{start=%#x, length=%#x, ptr=", mbuf.start, mbuf.length);
+       printaddr(ptr_to_kulong(mbuf.ptr));
+       tprints("}");
+}
 
-       case MEMWRITEOOB:
-       case MEMREADOOB:
-               if (!verbose(tcp) || umove(tcp, arg, &mbuf) < 0)
-                       return 0;
+static void
+decode_mtd_oob_buf64(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct mtd_oob_buf64 mbuf64;
 
-               tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", ptr=...}",
-                       mbuf.start, mbuf.length);
-               return 1;
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &mbuf64))
+               return;
 
-       case MEMWRITEOOB64:
-       case MEMREADOOB64:
-               if (!verbose(tcp) || umove(tcp, arg, &mbuf64) < 0)
-                       return 0;
+       tprintf("{start=%#" PRIx64 ", length=%#x, usr_ptr=%#" PRIx64 "}",
+               (uint64_t) mbuf64.start, mbuf64.length,
+               (uint64_t) mbuf64.usr_ptr);
+}
 
-               tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 ", ptr=...}",
-                       (uint64_t) mbuf64.start, (uint64_t) mbuf64.length);
-               return 1;
+static void
+decode_otp_info(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct otp_info oinfo;
 
-       case MEMGETREGIONINFO:
-               if (!verbose(tcp) || umove(tcp, arg, &rinfo) < 0)
-                       return 0;
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &oinfo))
+               return;
 
-               tprintf(", {offset=%#" PRIx32 ", erasesize=%#" PRIx32,
-                       rinfo.offset, rinfo.erasesize);
-               tprintf(", numblocks=%#" PRIx32 ", regionindex=%#" PRIx32 "}",
-                       rinfo.numblocks, rinfo.regionindex);
-               return 1;
+       tprintf("{start=%#x, length=%#x, locked=%u}",
+               oinfo.start, oinfo.length, oinfo.locked);
+}
 
-       case MEMGETOOBSEL:
-               if (!verbose(tcp) || umove(tcp, arg, &ninfo) < 0)
-                       return 0;
+static void
+decode_otp_select(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       unsigned int i;
 
-               tprints(", {useecc=");
-               printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
-               tprintf(", eccbytes=%#" PRIx32, ninfo.eccbytes);
-
-               tprints(", oobfree={");
-               for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
-                       if (i)
-                               tprints("}, ");
-                       tprints("{");
-                       for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
-                               if (j)
-                                       tprints(", ");
-                               tprintf("%#" PRIx32, ninfo.oobfree[i][j]);
-                       }
-               }
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &i))
+               return;
 
-               tprints("}}, eccpos={");
-               for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
-                       if (i)
-                               tprints(", ");
-                       tprintf("%#" PRIx32, ninfo.eccpos[i]);
-               }
+       tprints("[");
+       printxval(mtd_otp_options, i, "MTD_OTP_???");
+       tprints("]");
+}
 
-               tprints("}");
-               return 1;
+static void
+decode_mtd_write_req(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct mtd_write_req mreq;
 
-       case OTPGETREGIONINFO:
-       case OTPLOCK:
-               if (!verbose(tcp) || umove(tcp, arg, &oinfo) < 0)
-                       return 0;
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &mreq))
+               return;
+
+       tprintf("{start=%#" PRIx64 ", len=%#" PRIx64
+               ", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64
+               ", usr_oob=%#" PRIx64 ", mode=",
+               (uint64_t) mreq.start, (uint64_t) mreq.len,
+               (uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data,
+               (uint64_t) mreq.usr_oob);
+       printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???");
+       tprints("}");
+}
 
-               tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
-                       oinfo.start, oinfo.length, oinfo.locked);
-               return 1;
+static void
+decode_mtd_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct mtd_info_user minfo;
 
-       case ECCGETLAYOUT:
-               if (!verbose(tcp) || umove(tcp, arg, &nlay) < 0)
-                       return 0;
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &minfo))
+               return;
+
+       tprints("{type=");
+       printxval(mtd_type_options, minfo.type, "MTD_???");
+       tprints(", flags=");
+       printflags(mtd_flags_options, minfo.flags, "MTD_???");
+       tprintf(", size=%#x, erasesize=%#x, writesize=%#x, oobsize=%#x"
+               ", padding=%#" PRIx64 "}",
+               minfo.size, minfo.erasesize, minfo.writesize, minfo.oobsize,
+               (uint64_t) minfo.padding);
+}
 
-               tprintf(", {eccbytes=%#" PRIx32 ", eccpos={", nlay.eccbytes);
-               for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
-                       if (i)
-                               tprints(", ");
-                       tprintf("%#" PRIx32, nlay.eccpos[i]);
-               }
-               tprintf("}, oobavail=%#" PRIx32 ", oobfree={", nlay.oobavail);
-               for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
-                       if (i)
+static void
+decode_nand_oobinfo(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct nand_oobinfo ninfo;
+       unsigned int i, j;
+
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &ninfo))
+               return;
+
+       tprints("{useecc=");
+       printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
+       tprintf(", eccbytes=%#x", ninfo.eccbytes);
+
+       tprints(", oobfree={");
+       for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
+               if (i)
+                       tprints("}, ");
+               tprints("{");
+               for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
+                       if (j)
                                tprints(", ");
-                       tprintf("{offset=%#" PRIx32 ", length=%#" PRIx32 "}",
-                               nlay.oobfree[i].offset, nlay.oobfree[i].length);
+                       tprintf("%#x", ninfo.oobfree[i][j]);
                }
-               tprints("}");
-               return 1;
-
-       case ECCGETSTATS:
-               if (!verbose(tcp) || umove(tcp, arg, &estat) < 0)
-                       return 0;
-
-               tprintf(", {corrected=%#" PRIx32 ", failed=%#" PRIx32,
-                       estat.corrected, estat.failed);
-               tprintf(", badblocks=%#" PRIx32 ", bbtblocks=%#" PRIx32 "}",
-                       estat.badblocks, estat.bbtblocks);
-               return 1;
-
-       case MEMWRITE:
-               if (!verbose(tcp) || umove(tcp, arg, &mreq) < 0)
-                       return 0;
-
-               tprintf(", {start=%#" PRIx64 ", len=%#" PRIx64,
-                       (uint64_t) mreq.start, (uint64_t) mreq.len);
-               tprintf(", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64,
-                       (uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data);
-               tprintf(", usr_oob=%#" PRIx64 ", mode=",
-                       (uint64_t) mreq.usr_oob);
-               printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???");
-               tprints(", padding=...}");
-               return 1;
-
-       case OTPSELECT:
-               if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
-                       return 0;
-
-               tprints(", [");
-               printxval(mtd_otp_options, i, "MTD_OTP_???");
-               tprints("]");
-               return 1;
-
-       case MEMGETBADBLOCK:
-       case MEMSETBADBLOCK:
-               if (!verbose(tcp))
-                       return 0;
-
-               tprints(", ");
-               print_loff_t(tcp, arg);
-               return 1;
+       }
 
-       case OTPGETREGIONCOUNT:
-               if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
-                       return 0;
+       tprints("}}, eccpos={");
+       for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
+               if (i)
+                       tprints(", ");
+               tprintf("%#x", ninfo.eccpos[i]);
+       }
 
-               tprintf(", [%d]", i);
-               return 1;
+       tprints("}");
+}
 
-       case MTDFILEMODE:
-               /* XXX: process return value as enum mtd_file_modes */
+static void
+decode_nand_ecclayout_user(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct nand_ecclayout_user nlay;
+       unsigned int i;
 
-       case MEMGETREGIONCOUNT:
-               /* These ones take simple args, so let default printer handle it */
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &nlay))
+               return;
 
-       default:
-               return 0;
+       tprintf("{eccbytes=%#x, eccpos={", nlay.eccbytes);
+       for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
+               if (i)
+                       tprints(", ");
+               tprintf("%#x", nlay.eccpos[i]);
        }
+       tprintf("}, oobavail=%#x, oobfree={", nlay.oobavail);
+       for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
+               if (i)
+                       tprints(", ");
+               tprintf("{offset=%#x, length=%#x}",
+                       nlay.oobfree[i].offset, nlay.oobfree[i].length);
+       }
+       tprints("}");
 }
 
-static const struct xlat ubi_volume_types[] = {
-       { UBI_DYNAMIC_VOLUME,   "UBI_DYNAMIC_VOLUME"    },
-       { UBI_STATIC_VOLUME,    "UBI_STATIC_VOLUME"     },
-       { 0,                    NULL                    },
-};
+static void
+decode_mtd_ecc_stats(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+       struct mtd_ecc_stats es;
 
-static const struct xlat ubi_volume_props[] = {
-       { UBI_VOL_PROP_DIRECT_WRITE,    "UBI_VOL_PROP_DIRECT_WRITE"     },
-       { 0,                    NULL                    },
-};
+       tprints(", ");
+       if (umove_or_printaddr(tcp, addr, &es))
+               return;
 
-int ubi_ioctl(struct tcb *tcp, long code, long arg)
-{
-       struct ubi_mkvol_req mkvol;
-       struct ubi_rsvol_req rsvol;
-       struct ubi_rnvol_req rnvol;
-       struct ubi_attach_req attach;
-       struct ubi_map_req map;
-       struct ubi_set_vol_prop_req prop;
-       /* 4*(n-1) + 3 for quotes and NUL */
-       char vol_name[(UBI_MAX_VOLUME_NAME + 1) * 4];
-
-       if (entering(tcp))
-               return 0;
+       tprintf("{corrected=%#x, failed=%#x, badblocks=%#x, bbtblocks=%#x}",
+               es.corrected, es.failed, es.badblocks, es.bbtblocks);
+}
 
+MPERS_PRINTER_DECL(int, mtd_ioctl, struct tcb *const tcp,
+                  const unsigned int code, const kernel_ulong_t arg)
+{
        switch (code) {
-       case UBI_IOCMKVOL:
-               if (!verbose(tcp) || umove(tcp, arg, &mkvol) < 0)
-                       return 0;
+       case MEMERASE:
+       case MEMLOCK:
+       case MEMUNLOCK:
+       case MEMISLOCKED:
+               decode_erase_info_user(tcp, arg);
+               break;
 
-               tprintf(", {vol_id=%" PRIi32 ", alignment=%" PRIi32
-                       ", bytes=%" PRIi64 ", vol_type=", mkvol.vol_id,
-                       mkvol.alignment, (int64_t)mkvol.bytes);
-               printxval(ubi_volume_types, mkvol.vol_type, "UBI_???_VOLUME");
-               string_quote(mkvol.name, vol_name, -1, mkvol.name_len);
-               tprintf(", name_len=%" PRIi16 ", name=%s",
-                       mkvol.name_len, vol_name);
-               tprints("}");
-               return 1;
-
-       case UBI_IOCRSVOL:
-               if (!verbose(tcp) || umove(tcp, arg, &rsvol) < 0)
-                       return 0;
+       case MEMERASE64:
+               decode_erase_info_user64(tcp, arg);
+               break;
 
-               tprintf(", {vol_id=%" PRIi32 ", bytes=%" PRIi64 "}",
-                       rsvol.vol_id, (int64_t)rsvol.bytes);
-               return 1;
+       case MEMWRITEOOB:
+       case MEMREADOOB:
+               decode_mtd_oob_buf(tcp, arg);
+               break;
 
-       case UBI_IOCRNVOL: {
-               __s32 c;
+       case MEMWRITEOOB64:
+       case MEMREADOOB64:
+               decode_mtd_oob_buf64(tcp, arg);
+               break;
 
-               if (!verbose(tcp) || umove(tcp, arg, &rnvol) < 0)
+       case MEMWRITE:
+               decode_mtd_write_req(tcp, arg);
+               break;
+
+       case OTPGETREGIONINFO:
+               if (entering(tcp))
                        return 0;
+               /* fall through */
+       case OTPLOCK:
+               decode_otp_info(tcp, arg);
+               break;
 
-               tprintf(", {count=%" PRIi32 ", ents=[", rnvol.count);
-               for (c = 0; c < CLAMP(rnvol.count, 0, UBI_MAX_RNVOL); ++c) {
-                       if (c)
-                               tprints(", ");
-                       string_quote(rnvol.ents[c].name, vol_name, -1,
-                               rnvol.ents[c].name_len);
-                       tprintf("{vol_id=%" PRIi32 ", name_len=%" PRIi16
-                               ", name=%s}", rnvol.ents[c].vol_id,
-                               rnvol.ents[c].name_len, vol_name);
-               }
-               tprints("]}");
-               return 1;
-       }
+       case OTPSELECT:
+               decode_otp_select(tcp, arg);
+               break;
 
-       case UBI_IOCVOLUP: {
-               __s64 bytes;
+       case MTDFILEMODE:
+               tprints(", ");
+               printxval64(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
+               break;
 
-               if (!verbose(tcp) || umove(tcp, arg, &bytes) < 0)
-                       return 0;
+       case MEMGETBADBLOCK:
+       case MEMSETBADBLOCK:
+               tprints(", ");
+               printnum_int64(tcp, arg, "%" PRIu64);
+               break;
 
-               tprintf(", %" PRIi64, (int64_t)bytes);
-               return 1;
-       }
+       case MEMGETINFO:
+               if (entering(tcp))
+                       return 0;
+               decode_mtd_info_user(tcp, arg);
+               break;
 
-       case UBI_IOCATT:
-               if (!verbose(tcp) || umove(tcp, arg, &attach) < 0)
+       case MEMGETOOBSEL:
+               if (entering(tcp))
                        return 0;
+               decode_nand_oobinfo(tcp, arg);
+               break;
 
-               tprintf(", {ubi_num=%" PRIi32 ", mtd_num=%" PRIi32
-                       ", vid_hdr_offset=%" PRIi32
-                       ", max_beb_per1024=%" PRIi16 "}",
-                       attach.ubi_num, attach.mtd_num,
-                       attach.vid_hdr_offset, attach.max_beb_per1024);
-               return 1;
+       case ECCGETLAYOUT:
+               if (entering(tcp))
+                       return 0;
+               decode_nand_ecclayout_user(tcp, arg);
+               break;
 
-       case UBI_IOCEBMAP:
-               if (!verbose(tcp) || umove(tcp, arg, &map) < 0)
+       case ECCGETSTATS:
+               if (entering(tcp))
                        return 0;
+               decode_mtd_ecc_stats(tcp, arg);
+               break;
 
-               tprintf(", {lnum=%" PRIi32 ", dtype=%" PRIi8 "}",
-                       map.lnum, map.dtype);
-               return 1;
+       case OTPGETREGIONCOUNT:
+               if (entering(tcp))
+                       return 0;
+               tprints(", ");
+               printnum_int(tcp, arg, "%u");
+               break;
 
-       case UBI_IOCSETVOLPROP:
-               if (!verbose(tcp) || umove(tcp, arg, &prop) < 0)
+       case MEMGETREGIONCOUNT:
+               if (entering(tcp))
                        return 0;
+               tprints(", ");
+               printnum_int(tcp, arg, "%d");
+               break;
 
-               tprints(", {property=");
-               printxval(ubi_volume_props, prop.property, "UBI_VOL_PROP_???");
-               tprintf(", value=%#" PRIx64 "}", (uint64_t)prop.value);
-               return 1;
+       case MEMGETREGIONINFO:
+               if (entering(tcp)) {
+                       struct region_info_user rinfo;
 
-       case UBI_IOCRMVOL:
-       case UBI_IOCDET:
-       case UBI_IOCEBER:
-       case UBI_IOCEBCH:
-       case UBI_IOCEBUNMAP:
-       case UBI_IOCEBISMAP:
-               /* These ones take simple args, so let default printer handle it */
+                       tprints(", ");
+                       if (umove_or_printaddr(tcp, arg, &rinfo))
+                               break;
+                       tprintf("{regionindex=%#x", rinfo.regionindex);
+                       return 0;
+               } else {
+                       struct region_info_user rinfo;
+
+                       if (!syserror(tcp) && !umove(tcp, arg, &rinfo))
+                               tprintf(", offset=%#x"
+                                       ", erasesize=%#x"
+                                       ", numblocks=%#x}",
+                                       rinfo.offset,
+                                       rinfo.erasesize,
+                                       rinfo.numblocks);
+                       tprints("}");
+                       break;
+               }
 
        default:
-               return 0;
+               return RVAL_DECODED;
        }
+
+       return RVAL_DECODED | 1;
 }