summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorSerapheim Dimitropoulos <serapheim.dimitro@delphix.com>2017-01-11 08:47:43 -0800
committerPrakash Surya <prakash.surya@delphix.com>2018-02-15 15:07:01 -0800
commit3d580eda65b7c5ad75a73a93dceeebddfae06ec9 (patch)
tree41841d80b28d764c1545a08843722e474aa857a2 /usr/src
parenteea30b2609e6094732d948fa0c740852cb14c13d (diff)
downloadillumos-gate-3d580eda65b7c5ad75a73a93dceeebddfae06ec9.tar.gz
9091 MDB smart-write
Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Prashanth Sreenivasa <pks@delphix.com> Reviewed by: Robert Mustacchi <rm@joyent.com> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_cmds.c186
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_fmt.c4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_lex.l3
-rw-r--r--usr/src/man/man1/mdb.12
4 files changed, 191 insertions, 4 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
index 3b61c9ec3f..4314902056 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
@@ -28,7 +28,7 @@
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2015 Joyent, Inc. All rights reserved.
* Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
- * Copyright (c) 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
*/
#include <sys/elf.h>
@@ -198,6 +198,94 @@ write_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback)
return (addr + sizeof (n));
}
+/*
+ * Writes to objects of size 1, 2, 4, or 8 bytes. The function
+ * doesn't care if the object is a number or not (e.g. it could
+ * be a byte array, or a struct) as long as the size of the write
+ * is one of the aforementioned ones.
+ */
+static mdb_tgt_addr_t
+write_var_uint(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t val, size_t size,
+ uint_t rdback)
+{
+ if (size < sizeof (uint64_t)) {
+ uint64_t max_num = 1ULL << (size * NBBY);
+
+ if (val >= max_num) {
+ uint64_t write_len = 0;
+
+ /* count bytes needed for val */
+ while (val != 0) {
+ write_len++;
+ val >>= NBBY;
+ }
+
+ mdb_warn("value too big for the length of the write: "
+ "supplied %llu bytes but maximum is %llu bytes\n",
+ (u_longlong_t)write_len, (u_longlong_t)size);
+ return (addr);
+ }
+ }
+
+ switch (size) {
+ case 1:
+ return (write_uint8(as, addr, val, rdback));
+ case 2:
+ return (write_uint16(as, addr, val, rdback));
+ case 4:
+ return (write_uint32(as, addr, val, rdback));
+ case 8:
+ return (write_uint64(as, addr, val, rdback));
+ default:
+ mdb_warn("writes of size %u are not supported\n ", size);
+ return (addr);
+ }
+}
+
+static mdb_tgt_addr_t
+write_ctf_uint(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback)
+{
+ mdb_ctf_id_t mid;
+ size_t size;
+ ssize_t type_size;
+ int kind;
+
+ if (mdb_ctf_lookup_by_addr(addr, &mid) != 0) {
+ mdb_warn("no CTF data found at this address\n");
+ return (addr);
+ }
+
+ kind = mdb_ctf_type_kind(mid);
+ if (kind == CTF_ERR) {
+ mdb_warn("CTF data found but type kind could not be read");
+ return (addr);
+ }
+
+ if (kind == CTF_K_TYPEDEF) {
+ mdb_ctf_id_t temp_id;
+ if (mdb_ctf_type_resolve(mid, &temp_id) != 0) {
+ mdb_warn("failed to resolve type");
+ return (addr);
+ }
+ kind = mdb_ctf_type_kind(temp_id);
+ }
+
+ if (kind != CTF_K_INTEGER && kind != CTF_K_POINTER &&
+ kind != CTF_K_ENUM) {
+ mdb_warn("CTF type should be integer, pointer, or enum\n");
+ return (addr);
+ }
+
+ type_size = mdb_ctf_type_size(mid);
+ if (type_size < 0) {
+ mdb_warn("CTF data found but size could not be read");
+ return (addr);
+ }
+ size = type_size;
+
+ return (write_var_uint(as, addr, n, size, rdback));
+}
+
static int
write_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr,
int argc, const mdb_arg_t *argv)
@@ -222,6 +310,9 @@ write_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr,
case 'w':
write_value = write_uint16;
break;
+ case 'z':
+ write_value = write_ctf_uint;
+ break;
case 'W':
write_value = write_uint32;
break;
@@ -487,7 +578,7 @@ print_common(mdb_tgt_as_t as, uint_t flags, int argc, const mdb_arg_t *argv)
mdb_tgt_addr_t addr = mdb_nv_get_value(mdb.m_dot);
if (argc != 0 && argv->a_type == MDB_TYPE_CHAR) {
- if (strchr("vwWZ", argv->a_un.a_char))
+ if (strchr("vwzWZ", argv->a_un.a_char))
return (write_arglist(as, addr, argc, argv));
if (strchr("lLM", argv->a_un.a_char))
return (match_arglist(as, flags, addr, argc, argv));
@@ -2793,6 +2884,94 @@ cmd_delete(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (ve_delete_spec(&spec));
}
+static int
+cmd_write(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ mdb_tgt_as_t as;
+ int rdback = mdb.m_flags & MDB_FL_READBACK;
+ mdb_tgt_addr_t naddr;
+ size_t forced_size = 0;
+ boolean_t opt_p, opt_o, opt_l;
+ uint64_t val = 0;
+ int i;
+
+ opt_p = opt_o = opt_l = B_FALSE;
+
+ i = mdb_getopts(argc, argv,
+ 'p', MDB_OPT_SETBITS, B_TRUE, &opt_p,
+ 'o', MDB_OPT_SETBITS, B_TRUE, &opt_o,
+ 'l', MDB_OPT_UINTPTR_SET, &opt_l, (uintptr_t *)&forced_size, NULL);
+
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ if (opt_p && opt_o) {
+ mdb_warn("-o and -p are incompatible\n");
+ return (DCMD_USAGE);
+ }
+
+ argc -= i;
+ argv += i;
+
+ if (argc == 0)
+ return (DCMD_USAGE);
+
+ switch (argv[0].a_type) {
+ case MDB_TYPE_STRING:
+ val = mdb_strtoull(argv[0].a_un.a_str);
+ break;
+ case MDB_TYPE_IMMEDIATE:
+ val = argv[0].a_un.a_val;
+ break;
+ default:
+ return (DCMD_USAGE);
+ }
+
+ if (opt_p)
+ as = MDB_TGT_AS_PHYS;
+ else if (opt_o)
+ as = MDB_TGT_AS_FILE;
+ else
+ as = MDB_TGT_AS_VIRT;
+
+ if (opt_l)
+ naddr = write_var_uint(as, addr, val, forced_size, rdback);
+ else
+ naddr = write_ctf_uint(as, addr, val, rdback);
+
+ if (addr == naddr) {
+ mdb_warn("failed to write %llr at address %#llx", val, addr);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+void
+write_help(void)
+{
+ mdb_printf(
+ "-l length force a write with the specified length in bytes\n"
+ "-o write data to the object file location specified\n"
+ "-p write data to the physical address specified\n"
+ "\n"
+ "Attempts to write the given value to the address provided.\n"
+ "If -l is not specified, the address must be the position of a\n"
+ "symbol that is either of integer, pointer, or enum type. The\n"
+ "type and the size of the symbol are inferred by the CTF found\n"
+ "in the provided address. The length of the write is guaranteed\n"
+ "to be the inferred size of the symbol.\n"
+ "\n"
+ "If no CTF data exists, or the address provided is not a symbol\n"
+ "of integer or pointer type, then the write fails. At that point\n"
+ "the user can force the write by using the '-l' option and\n"
+ "specifying its length.\n"
+ "\n"
+ "Note that forced writes with a length that are bigger than\n"
+ "the size of the biggest data pointer supported are not allowed."
+ "\n");
+}
+
static void
srcexec_file_help(void)
{
@@ -2999,6 +3178,9 @@ const mdb_dcmd_t mdb_dcmd_builtins[] = {
cmd_whatis, whatis_help },
{ "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which },
{ "which", "[-v] name ...", "show source of walk or dcmd", cmd_which },
+ { "write", "?[-op] [-l len] value",
+ "write value to the provided memory location", cmd_write,
+ write_help },
{ "xdata", NULL, "print list of external data buffers", cmd_xdata },
#ifdef _KMDB
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
index 539a4c249e..78d27bdcb9 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
@@ -22,6 +22,7 @@
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2016 Joyent, Inc.
+ * Copyright (c) 2017 by Delphix. All rights reserved.
*/
/*
@@ -118,6 +119,7 @@ static const char help_match32[] = "int";
static const char help_match64[] = "long long";
static const char help_match16[] = "short";
static const char help_uintptr[] = "hexadecimal uintptr_t";
+static const char help_ctf[] = "whose size is inferred by CTF info";
/*ARGSUSED*/
static mdb_tgt_addr_t
@@ -618,7 +620,7 @@ static const mdb_fmt_desc_t fmttab[] = {
{ FMT_PRINTF|FMT_WRITE, "%-8hr", NULL, 2 }, /* 119 = w */
{ FMT_PRINTF, "%-8hx", NULL, 2 }, /* 120 = x */
{ FMT_FUNC, FUNCP(fmt_time64), help_time64, 8 }, /* 121 = y */
- { FMT_NONE, NULL, NULL, 0 }, /* 122 = z */
+ { FMT_WRITE, NULL, help_ctf, 0 }, /* 122 = z */
};
mdb_tgt_addr_t
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_lex.l b/usr/src/cmd/mdb/common/mdb/mdb_lex.l
index b9bee245b6..e777039c7b 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_lex.l
+++ b/usr/src/cmd/mdb/common/mdb/mdb_lex.l
@@ -27,6 +27,7 @@
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2017 by Delphix. All rights reserved.
*/
#include <sys/types.h>
@@ -213,7 +214,7 @@ RGX_COMMENT "//".*\n
return (MDB_TOK_DCMD);
}
-<S_INITIAL>[/\\?][ \t]*[vwWZlLM] {
+<S_INITIAL>[/\\?][ \t]*[vwzWZlLM] {
/*
* Format verb followed by write or match signifier -- switch
* to the value list state and return the verb character. We
diff --git a/usr/src/man/man1/mdb.1 b/usr/src/man/man1/mdb.1
index a4bb05a51e..653404dc77 100644
--- a/usr/src/man/man1/mdb.1
+++ b/usr/src/man/man1/mdb.1
@@ -1,6 +1,7 @@
'\" te
.\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2012, Joyent, Inc. All Rights Reserved.
+.\" Copyright (c) 2014, 2017 by Delphix. All rights reserved.
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
@@ -1379,6 +1380,7 @@ v decimal signed int (1 byte)
w default radix unsigned short (2 bytes)
x hexadecimal short (2 bytes)
y decoded time64_t (8 bytes)
+z write whose size is inferred by CTF info (variable size)
.TE
.sp