/*
* 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
#include "defs.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 */
#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
+
+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_otp_options.h"
#include "xlat/mtd_nandecc_options.h"
-int
-mtd_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
+static void
+decode_erase_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
{
- if (!verbose(tcp))
- return RVAL_DECODED;
+ struct erase_info_user einfo;
- switch (code) {
- case MEMERASE:
- case MEMLOCK:
- case MEMUNLOCK:
- case MEMISLOCKED: {
- struct erase_info_user einfo;
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &einfo))
+ return;
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &einfo))
- break;
+ tprintf("{start=%#x, length=%#x}", einfo.start, einfo.length);
+}
- tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 "}",
- einfo.start, einfo.length);
- break;
- }
+static void
+decode_erase_info_user64(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct erase_info_user64 einfo64;
- case MEMERASE64: {
- struct erase_info_user64 einfo64;
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &einfo64))
+ return;
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &einfo64))
- break;
+ tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}",
+ (uint64_t) einfo64.start, (uint64_t) einfo64.length);
+}
- tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}",
- (uint64_t) einfo64.start, (uint64_t) einfo64.length);
- break;
- }
+static void
+decode_mtd_oob_buf(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct_mtd_oob_buf mbuf;
- case MEMWRITEOOB:
- case MEMREADOOB: {
- struct mtd_oob_buf mbuf;
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &mbuf))
+ return;
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &mbuf))
- break;
+ tprintf("{start=%#x, length=%#x, ptr=", mbuf.start, mbuf.length);
+ printaddr(ptr_to_kulong(mbuf.ptr));
+ tprints("}");
+}
- tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 ", ptr=...}",
- mbuf.start, mbuf.length);
- break;
- }
+static void
+decode_mtd_oob_buf64(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_oob_buf64 mbuf64;
- case MEMWRITEOOB64:
- case MEMREADOOB64: {
- struct mtd_oob_buf64 mbuf64;
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &mbuf64))
+ return;
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &mbuf64))
- break;
+ 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);
- break;
+static void
+decode_otp_info(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct otp_info oinfo;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &oinfo))
+ return;
+
+ tprintf("{start=%#x, length=%#x, locked=%u}",
+ oinfo.start, oinfo.length, oinfo.locked);
+}
+
+static void
+decode_otp_select(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ unsigned int i;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &i))
+ return;
+
+ tprints("[");
+ printxval(mtd_otp_options, i, "MTD_OTP_???");
+ tprints("]");
+}
+
+static void
+decode_mtd_write_req(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_write_req mreq;
+
+ 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("}");
+}
+
+static void
+decode_mtd_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_info_user minfo;
+
+ 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);
+}
+
+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("%#x", ninfo.oobfree[i][j]);
+ }
+ }
+
+ tprints("}}, eccpos={");
+ for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
+ if (i)
+ tprints(", ");
+ tprintf("%#x", ninfo.eccpos[i]);
}
- case MEMGETREGIONINFO: {
- struct region_info_user rinfo;
+ tprints("}");
+}
- if (entering(tcp)) {
+static void
+decode_nand_ecclayout_user(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct nand_ecclayout_user nlay;
+ unsigned int i;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &nlay))
+ return;
+
+ tprintf("{eccbytes=%#x, eccpos={", nlay.eccbytes);
+ for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
+ if (i)
tprints(", ");
- if (umove_or_printaddr(tcp, arg, &rinfo))
- break;
- tprintf("{regionindex=%#x", rinfo.regionindex);
- return 1;
- } else {
- if (syserror(tcp)) {
- tprints("}");
- break;
- }
- if (umove(tcp, arg, &rinfo) < 0) {
- tprints(", ???}");
- break;
- }
- tprintf(", offset=%#x, erasesize=%#x, numblocks=%#x}",
- rinfo.offset, rinfo.erasesize, rinfo.numblocks);
- break;
- }
+ 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("}");
+}
- case OTPLOCK: {
- struct otp_info oinfo;
+static void
+decode_mtd_ecc_stats(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_ecc_stats es;
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &oinfo))
- break;
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &es))
+ return;
+
+ tprintf("{corrected=%#x, failed=%#x, badblocks=%#x, bbtblocks=%#x}",
+ es.corrected, es.failed, es.badblocks, es.bbtblocks);
+}
- tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
- oinfo.start, oinfo.length, oinfo.locked);
+MPERS_PRINTER_DECL(int, mtd_ioctl, struct tcb *const tcp,
+ const unsigned int code, const kernel_ulong_t arg)
+{
+ switch (code) {
+ case MEMERASE:
+ case MEMLOCK:
+ case MEMUNLOCK:
+ case MEMISLOCKED:
+ decode_erase_info_user(tcp, arg);
break;
- }
- case MEMWRITE: {
- struct mtd_write_req mreq;
+ case MEMERASE64:
+ decode_erase_info_user64(tcp, arg);
+ break;
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &mreq))
- break;
+ case MEMWRITEOOB:
+ case MEMREADOOB:
+ decode_mtd_oob_buf(tcp, arg);
+ break;
- 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=...}");
+ case MEMWRITEOOB64:
+ case MEMREADOOB64:
+ decode_mtd_oob_buf64(tcp, arg);
break;
- }
- case OTPSELECT: {
- unsigned int i;
+ case MEMWRITE:
+ decode_mtd_write_req(tcp, arg);
+ break;
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &i))
- break;
+ case OTPGETREGIONINFO:
+ if (entering(tcp))
+ return 0;
+ /* fall through */
+ case OTPLOCK:
+ decode_otp_info(tcp, arg);
+ break;
- tprints("[");
- printxval(mtd_otp_options, i, "MTD_OTP_???");
- tprints("]");
+ case OTPSELECT:
+ decode_otp_select(tcp, arg);
break;
- }
case MTDFILEMODE:
tprints(", ");
- printxval_long(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
+ printxval64(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
break;
case MEMGETBADBLOCK:
printnum_int64(tcp, arg, "%" PRIu64);
break;
- case MEMGETINFO: {
- struct mtd_info_user minfo;
-
+ case MEMGETINFO:
if (entering(tcp))
return 0;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &minfo))
- break;
-
- 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);
+ decode_mtd_info_user(tcp, arg);
break;
- }
-
- case MEMGETOOBSEL: {
- struct nand_oobinfo ninfo;
- unsigned int i;
+ case MEMGETOOBSEL:
if (entering(tcp))
return 0;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &ninfo))
- break;
-
- 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) {
- unsigned int j;
-
- if (i)
- tprints("}, ");
- tprints("{");
- for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
- if (j)
- tprints(", ");
- tprintf("%#" PRIx32, ninfo.oobfree[i][j]);
- }
- }
-
- tprints("}}, eccpos={");
- for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
- if (i)
- tprints(", ");
- tprintf("%#" PRIx32, ninfo.eccpos[i]);
- }
-
- tprints("}");
+ decode_nand_oobinfo(tcp, arg);
break;
- }
-
- case OTPGETREGIONINFO: {
- struct otp_info oinfo;
+ case ECCGETLAYOUT:
if (entering(tcp))
return 0;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &oinfo))
- break;
-
- tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
- oinfo.start, oinfo.length, oinfo.locked);
+ decode_nand_ecclayout_user(tcp, arg);
break;
- }
-
- case ECCGETLAYOUT: {
- struct nand_ecclayout_user nlay;
- unsigned int i;
+ case ECCGETSTATS:
if (entering(tcp))
return 0;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &nlay))
- break;
-
- 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)
- tprints(", ");
- tprintf("{offset=%#" PRIx32 ", length=%#" PRIx32 "}",
- nlay.oobfree[i].offset, nlay.oobfree[i].length);
- }
- tprints("}");
+ decode_mtd_ecc_stats(tcp, arg);
break;
- }
-
- case ECCGETSTATS: {
- struct mtd_ecc_stats estat;
-
- if (entering(tcp))
- return 0;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &estat))
- break;
-
- tprintf("{corrected=%#" PRIx32 ", failed=%#" PRIx32,
- estat.corrected, estat.failed);
- tprintf(", badblocks=%#" PRIx32 ", bbtblocks=%#" PRIx32 "}",
- estat.badblocks, estat.bbtblocks);
- break;
- }
case OTPGETREGIONCOUNT:
if (entering(tcp))
return 0;
-
tprints(", ");
printnum_int(tcp, arg, "%u");
break;
case MEMGETREGIONCOUNT:
if (entering(tcp))
return 0;
-
tprints(", ");
printnum_int(tcp, arg, "%d");
break;
- default:
- return RVAL_DECODED;
- }
-
- return RVAL_DECODED | 1;
-}
-
-#include "xlat/ubi_volume_types.h"
-#include "xlat/ubi_volume_props.h"
-
-int
-ubi_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
-{
- if (!verbose(tcp))
- return RVAL_DECODED;
-
- switch (code) {
- case UBI_IOCMKVOL:
+ case MEMGETREGIONINFO:
if (entering(tcp)) {
- struct ubi_mkvol_req mkvol;
+ struct region_info_user rinfo;
tprints(", ");
- if (umove_or_printaddr(tcp, arg, &mkvol))
+ if (umove_or_printaddr(tcp, arg, &rinfo))
break;
-
- tprintf("{vol_id=%" PRIi32 ", alignment=%" PRIi32
- ", bytes=%" PRIi64 ", vol_type=", mkvol.vol_id,
- mkvol.alignment, (int64_t)mkvol.bytes);
- printxval(ubi_volume_types,
- (uint8_t) mkvol.vol_type, "UBI_???_VOLUME");
- tprintf(", name_len=%" PRIi16 ", name=", mkvol.name_len);
- if (print_quoted_string(mkvol.name,
- CLAMP(mkvol.name_len, 0, UBI_MAX_VOLUME_NAME),
- QUOTE_0_TERMINATED) > 0) {
- tprints("...");
- }
- tprints("}");
- return 1;
- }
- if (!syserror(tcp)) {
- tprints(" => ");
- printnum_int(tcp, arg, "%d");
- }
- break;
-
- case UBI_IOCRSVOL: {
- struct ubi_rsvol_req rsvol;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &rsvol))
- break;
-
- tprintf("{vol_id=%" PRIi32 ", bytes=%" PRIi64 "}",
- rsvol.vol_id, (int64_t)rsvol.bytes);
- break;
- }
-
- case UBI_IOCRNVOL: {
- struct ubi_rnvol_req rnvol;
- int c;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &rnvol))
- break;
-
- tprintf("{count=%" PRIi32 ", ents=[", rnvol.count);
- for (c = 0; c < CLAMP(rnvol.count, 0, UBI_MAX_RNVOL); ++c) {
- if (c)
- tprints(", ");
- tprintf("{vol_id=%" PRIi32 ", name_len=%" PRIi16
- ", name=", rnvol.ents[c].vol_id,
- rnvol.ents[c].name_len);
- if (print_quoted_string(rnvol.ents[c].name,
- CLAMP(rnvol.ents[c].name_len, 0, UBI_MAX_VOLUME_NAME),
- QUOTE_0_TERMINATED) > 0) {
- tprints("...");
- }
+ 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("}");
- }
- tprints("]}");
- break;
- }
-
- case UBI_IOCEBCH: {
- struct ubi_leb_change_req leb;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &leb))
break;
-
- tprintf("{lnum=%d, bytes=%d}", leb.lnum, leb.bytes);
- break;
- }
-
- case UBI_IOCATT:
- if (entering(tcp)) {
- struct ubi_attach_req attach;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &attach))
- 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;
- }
- if (!syserror(tcp)) {
- tprints(" => ");
- printnum_int(tcp, arg, "%d");
}
- break;
-
- case UBI_IOCEBMAP: {
- struct ubi_map_req map;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &map))
- break;
-
- tprintf("{lnum=%" PRIi32 ", dtype=%" PRIi8 "}",
- map.lnum, map.dtype);
- break;
- }
-
- case UBI_IOCSETVOLPROP: {
- struct ubi_set_vol_prop_req prop;
-
- tprints(", ");
- if (umove_or_printaddr(tcp, arg, &prop))
- break;
-
- tprints("{property=");
- printxval(ubi_volume_props, prop.property, "UBI_VOL_PROP_???");
- tprintf(", value=%#" PRIx64 "}", (uint64_t)prop.value);
- break;
- }
-
-
- case UBI_IOCVOLUP:
- tprints(", ");
- printnum_int64(tcp, arg, "%" PRIi64);
- break;
-
- case UBI_IOCDET:
- case UBI_IOCEBER:
- case UBI_IOCEBISMAP:
- case UBI_IOCEBUNMAP:
- case UBI_IOCRMVOL:
- tprints(", ");
- printnum_int(tcp, arg, "%d");
- break;
-
-#ifdef UBI_IOCVOLCRBLK
- case UBI_IOCVOLCRBLK:
-#endif
-#ifdef UBI_IOCVOLRMBLK
- case UBI_IOCVOLRMBLK:
-#endif
- /* no arguments */
- break;
default:
return RVAL_DECODED;