--- old/usr/src/cmd/mdb/common/mdb/mdb_fmt.c	Fri Mar  6 04:33:11 2020
+++ new/usr/src/cmd/mdb/common/mdb/mdb_fmt.c	Fri Mar  6 04:33:11 2020
@@ -21,7 +21,7 @@
 /*
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
  * Copyright (c) 2017 by Delphix. All rights reserved.
  */
 
@@ -733,7 +733,7 @@
 		 * Unless a format has explicitly opted out, we force autowrap
 		 * for the duration of mdb_fmt_print().
 		 */
-		mdb.m_flags |= MDB_FL_AUTOWRAP;
+		mdb_iob_set_autowrap(mdb.m_out);
 	}
 
 	switch (FMT_TYPE(fp->f_type)) {
--- old/usr/src/cmd/mdb/common/mdb/mdb_io.c	Fri Mar  6 04:33:11 2020
+++ new/usr/src/cmd/mdb/common/mdb/mdb_io.c	Fri Mar  6 04:33:11 2020
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright (c) 2019, Joyent, Inc. All rights reserved.
+ * Copyright 2020 Joyent, Inc.
  * Copyright (c) 2016 by Delphix. All rights reserved.
  */
 
@@ -1777,6 +1777,27 @@
 	return (nbytes);
 }
 
+/*
+ * Return how many bytes we can copy into our buffer, limited by either cols or
+ * bufsiz depending on whether AUTOWRAP is on.  Note that typically,
+ * mdb_iob_set_autowrap() will have already checked for an existing
+ * "->iob_nbytes > ->iob_cols" situation, but we double check here anyway.
+ */
+static size_t
+iob_bufleft(mdb_iob_t *iob)
+{
+	if (IOB_AUTOWRAP(iob)) {
+		if (iob->iob_cols < iob->iob_nbytes) {
+			mdb_iob_nl(iob);
+			ASSERT(iob->iob_cols >= iob->iob_nbytes);
+		}
+		return (iob->iob_cols - iob->iob_nbytes);
+	}
+
+	ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
+	return (iob->iob_bufsiz - iob->iob_nbytes);
+}
+
 void
 mdb_iob_nputs(mdb_iob_t *iob, const char *s, size_t nbytes)
 {
@@ -1810,20 +1831,11 @@
 	}
 
 	/*
-	 * For a given string component, we determine how many bytes (n) we can
-	 * copy into our buffer (limited by either cols or bufsiz depending
-	 * on whether AUTOWRAP is on), copy a chunk into the buffer, and
+	 * For a given string component, we copy a chunk into the buffer, and
 	 * flush the buffer if we reach the end of a line.
 	 */
 	while (nleft != 0) {
-		if (IOB_AUTOWRAP(iob)) {
-			ASSERT(iob->iob_cols >= iob->iob_nbytes);
-			n = iob->iob_cols - iob->iob_nbytes;
-		} else {
-			ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
-			n = iob->iob_bufsiz - iob->iob_nbytes;
-		}
-
+		n = iob_bufleft(iob);
 		m = MIN(nleft, n); /* copy at most n bytes in this pass */
 
 		bcopy(q, iob->iob_bufp, m);
@@ -1884,14 +1896,7 @@
 	ASSERT(iob->iob_flags & MDB_IOB_WRONLY);
 
 	while (nfill != 0) {
-		if (IOB_AUTOWRAP(iob)) {
-			ASSERT(iob->iob_cols >= iob->iob_nbytes);
-			n = iob->iob_cols - iob->iob_nbytes;
-		} else {
-			ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
-			n = iob->iob_bufsiz - iob->iob_nbytes;
-		}
-
+		n = iob_bufleft(iob);
 		m = MIN(nfill, n); /* fill at most n bytes in this pass */
 
 		for (i = 0; i < m; i++)
@@ -2169,6 +2174,26 @@
 }
 
 /*
+ * This only enables autowrap for iobs that are already autowrap themselves such
+ * as mdb.m_out typically.
+ *
+ * Note that we might be the middle of the iob buffer at this point, and
+ * specifically, iob->iob_nbytes could be more than iob->iob_cols.  As that's
+ * not a valid situation, we may need to do an autowrap *now*.
+ *
+ * In theory, we would need to do this across all MDB_IOB_AUTOWRAP iob's;
+ * instead, we have a failsafe in iob_bufleft().
+ */
+void
+mdb_iob_set_autowrap(mdb_iob_t *iob)
+{
+	mdb.m_flags |= MDB_FL_AUTOWRAP;
+	if (IOB_WRAPNOW(iob, 0))
+		mdb_iob_nl(iob);
+	ASSERT(iob->iob_cols >= iob->iob_nbytes);
+}
+
+/*
  * Stub functions for i/o backend implementors: these stubs either act as
  * pass-through no-ops or return ENOTSUP as appropriate.
  */
@@ -2267,14 +2292,14 @@
 /*
  * Iterate over the varargs. The first item indicates the mode:
  * MDB_TBL_PRNT
- * 	pull out the next vararg as a const char * and pass it and the
- * 	remaining varargs to iob_doprnt; if we want to print the column,
- * 	direct the output to mdb.m_out otherwise direct it to mdb.m_null
+ *	pull out the next vararg as a const char * and pass it and the
+ *	remaining varargs to iob_doprnt; if we want to print the column,
+ *	direct the output to mdb.m_out otherwise direct it to mdb.m_null
  *
  * MDB_TBL_FUNC
- * 	pull out the next vararg as type mdb_table_print_f and the
- * 	following one as a void * argument to the function; call the
- * 	function with the given argument if we want to print the column
+ *	pull out the next vararg as type mdb_table_print_f and the
+ *	following one as a void * argument to the function; call the
+ *	function with the given argument if we want to print the column
  *
  * The second item indicates the flag; if the flag is set in the flags
  * argument, then the column is printed. A flag value of 0 indicates
--- old/usr/src/cmd/mdb/common/mdb/mdb_io.h	Fri Mar  6 04:33:11 2020
+++ new/usr/src/cmd/mdb/common/mdb/mdb_io.h	Fri Mar  6 04:33:11 2020
@@ -21,13 +21,13 @@
 /*
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2020 Joyent, Inc.
  */
 
 #ifndef	_MDB_IO_H
 #define	_MDB_IO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -149,6 +149,8 @@
 extern size_t mdb_iob_gettabstop(mdb_iob_t *);
 extern size_t mdb_iob_getmargin(mdb_iob_t *);
 
+extern void mdb_iob_set_autowrap(mdb_iob_t *);
+
 extern void mdb_iob_stack_create(mdb_iob_stack_t *);
 extern void mdb_iob_stack_destroy(mdb_iob_stack_t *);
 extern void mdb_iob_stack_push(mdb_iob_stack_t *, mdb_iob_t *, size_t);
--- old/usr/src/cmd/mdb/common/mdb/mdb_print.c	Fri Mar  6 04:33:11 2020
+++ new/usr/src/cmd/mdb/common/mdb/mdb_print.c	Fri Mar  6 04:33:12 2020
@@ -25,7 +25,7 @@
 
 /*
  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
  * Copyright (c) 2014 Nexenta Systems, Inc. All rights reserved.
  */
 
@@ -931,6 +931,30 @@
 }
 
 /*
+ * We want to print an escaped char as e.g. '\0'. We don't use mdb_fmt_print()
+ * as it won't get auto-wrap right here (although even now, we don't include any
+ * trailing comma).
+ */
+static int
+print_char_val(mdb_tgt_addr_t addr, printarg_t *pap)
+{
+	char cval;
+	char *s;
+
+	if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &cval, 1, addr) != 1)
+		return (1);
+
+	if (mdb.m_flags & MDB_FL_ADB)
+		s = strchr2adb(&cval, 1);
+	else
+		s = strchr2esc(&cval, 1);
+
+	mdb_printf("'%s'", s);
+	strfree(s);
+	return (0);
+}
+
+/*
  * Print out a character or integer value.  We use some simple heuristics,
  * described below, to determine the appropriate radix to use for output.
  */
@@ -971,14 +995,8 @@
 	if (size > 8 || (ep->cte_bits % NBBY) != 0 || (size & (size - 1)) != 0)
 		return (print_bitfield(off, pap, ep));
 
-	if (IS_CHAR(*ep)) {
-		mdb_printf("'");
-		if (mdb_fmt_print(pap->pa_tgt, pap->pa_as,
-		    addr, 1, 'C') == addr)
-			return (1);
-		mdb_printf("'");
-		return (0);
-	}
+	if (IS_CHAR(*ep))
+		return (print_char_val(addr, pap));
 
 	if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size, addr) != size) {
 		mdb_warn("failed to read %lu bytes at %llx",
--- old/usr/src/cmd/mdb/common/mdb/mdb_set.c	Fri Mar  6 04:33:12 2020
+++ new/usr/src/cmd/mdb/common/mdb/mdb_set.c	Fri Mar  6 04:33:12 2020
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
  */
 
 /*
@@ -275,7 +275,7 @@
 	 * we enable it for the duration of the command.
 	 */
 	oflags = mdb.m_flags;
-	mdb.m_flags |= MDB_FL_AUTOWRAP;
+	mdb_iob_set_autowrap(mdb.m_out);
 
 	mdb_printf("follow_exec_mode=");
 	switch (mdb.m_execmode) {
