xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_fmt.c (revision 24537d3ef87e4452da693fc3143ef18a1a0f3cac)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2020 Joyent, Inc.
25  * Copyright (c) 2017 by Delphix. All rights reserved.
26  */
27 
28 /*
29  * Format String Decoder
30  *
31  * This file provides the core engine for converting strings of format
32  * characters into formatted output.  The various format dcmds invoke the
33  * mdb_fmt_print() function below with a target, address space identifier,
34  * address, count, and format character, and it reads the required data from
35  * the target and prints the formatted output to stdout.  Since nearly two
36  * thirds of the format characters can be expressed as simple printf format
37  * strings, we implement the engine using the lookup table below.  Each entry
38  * provides either a pointer to a printf format string or a pointer to a
39  * function to perform special processing.  For the printf case, the
40  * corresponding data size in bytes is also supplied.  The printf processing
41  * code handles 1, 2, 4, and 8-byte reads into an unsigned integer container
42  * of the given size, and then simply calls mdb_iob_printf with the integer
43  * and format string. This handles all printf cases, except when unsigned
44  * promotion of an integer type in the varargs list does not perform the
45  * conversion we require to get the proper result.  With the current set of
46  * format characters, this case only occurs twice: we need a 4-byte float
47  * to get promoted to 8-byte double for the 'f' format so it can be
48  * correctly formatted by %f, and we need a 1-byte int8_t to get promoted
49  * with sign extension to a 4-byte int32_t for the 'v' format so it can be
50  * correctly formatted by %d.  We provide explicit functions to handle these
51  * cases, as well as to handle special format characters such as 'i', etc.
52  * We also provide a cmd_formats() dcmd function below which prints a table
53  * of the output formats and their sizes.  Format characters that provide
54  * custom functions provide their help description string explicitly.  All
55  * the printf formats have their help strings generated automatically by
56  * our printf "unparser" mdb_iob_format2str().
57  */
58 
59 #include <mdb/mdb_types.h>
60 #include <mdb/mdb_target.h>
61 #include <mdb/mdb_io.h>
62 #include <mdb/mdb_err.h>
63 #include <mdb/mdb_string.h>
64 #include <mdb/mdb_modapi.h>
65 #include <mdb/mdb.h>
66 
67 #define	FUNCP(p)	((void *)(p))	/* Cast to f_ptr type */
68 #define	SZ_NONE		((size_t)-1L)	/* Format does not change dot */
69 
70 typedef mdb_tgt_addr_t mdb_fmt_func_f(mdb_tgt_t *,
71     mdb_tgt_as_t, mdb_tgt_addr_t, size_t);
72 
73 /*
74  * There are several 'special' characters that are handled outside of
75  * mdb_fmt_print().  These are characters that write (vwWZ) and characters that
76  * match (lLM).  We include them here so that ::formats can display an
77  * appropriate message, but they are handled specially by write_arglist() and
78  * match_arglist() in mdb_cmds.c.
79  */
80 #define	FMT_NONE	0x0	/* Format character is not supported */
81 #define	FMT_FUNC	0x1	/* f_ptr is a mdb_fmt_func_f to call */
82 #define	FMT_PRINTF	0x2	/* f_ptr is a const char * format string */
83 #define	FMT_MATCH	0x4	/* Match command (not supported here) */
84 #define	FMT_WRITE	0x8	/* Command writes to address space */
85 #define	FMT_NOAUTOWRAP	0x10	/* Autowrap should not be autoenabled */
86 
87 #define	FMT_TYPE(x)	((x) & 0x7) /* Excludes modifying flags */
88 
89 typedef struct mdb_fmt_desc {
90 	int f_type;		/* Type of format (see above) */
91 	void *f_ptr;		/* Data pointer (see above) */
92 	const char *f_help;	/* Additional help string */
93 	size_t f_size;		/* Size of type in bytes, or SZ_NONE */
94 	boolean_t f_float;	/* Is this a floating point type */
95 } mdb_fmt_desc_t;
96 
97 static const char help_plus[] = "increment dot by the count";
98 static const char help_minus[] = "decrement dot by the count";
99 static const char help_escchr[] = "character using C character notation";
100 static const char help_swapint[] = "swap bytes and shorts";
101 static const char help_dotinstr[] = "address and disassembled instruction";
102 static const char help_instr[] = "disassembled instruction";
103 static const char help_escstr[] = "string using C string notation";
104 static const char help_time32[] = "decoded time32_t";
105 static const char help_carat[] = "decrement dot by increment * count";
106 static const char help_dot[] = "dot as symbol+offset";
107 #ifndef _KMDB
108 static const char help_f[] = "float";
109 #endif
110 static const char help_swapshort[] = "swap bytes";
111 static const char help_nl[] = "newline";
112 static const char help_ws[] = "whitespace";
113 static const char help_rawstr[] = "raw string";
114 static const char help_tab[] = "horizontal tab";
115 static const char help_sdbyte[] = "decimal signed int";
116 static const char help_time64[] = "decoded time64_t";
117 static const char help_binary[] = "binary unsigned long long";
118 static const char help_hex64[] = "hexadecimal long long";
119 static const char help_match32[] = "int";
120 static const char help_match64[] = "long long";
121 static const char help_match16[] = "short";
122 static const char help_uintptr[] = "hexadecimal uintptr_t";
123 static const char help_ctf[] = "whose size is inferred by CTF info";
124 static const char help_jazzed[] = "jazzed-up binary unsigned long long";
125 
126 /*ARGSUSED*/
127 static mdb_tgt_addr_t
fmt_dot(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)128 fmt_dot(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
129 {
130 	uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
131 	char buf[24];
132 
133 	mdb_iob_clrflags(mdb.m_out, oflags);
134 
135 	if (mdb.m_flags & MDB_FL_PSYM) {
136 		while (cnt-- != 0)
137 			mdb_iob_printf(mdb.m_out, "%-#16lla%16T", addr);
138 	} else {
139 		(void) mdb_iob_snprintf(buf, sizeof (buf),
140 		    "%#llx:", (u_longlong_t)addr);
141 		while (cnt-- != 0)
142 			mdb_iob_printf(mdb.m_out, "%-16s%16T", buf);
143 	}
144 
145 	mdb_iob_setflags(mdb.m_out, oflags);
146 	mdb_nv_set_value(mdb.m_rvalue, addr);
147 	return (addr);
148 }
149 
150 #ifndef _KMDB
151 static mdb_tgt_addr_t
fmt_float(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)152 fmt_float(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
153 {
154 	float f;
155 	/*
156 	 * We need to handle float as a special case because we need it to be
157 	 * promoted to a double by virtue of appearing as a parameter, and all
158 	 * our generic format handling below is based on integer types.
159 	 */
160 	while (cnt-- != 0) {
161 		if (mdb_tgt_aread(t, as, &f, sizeof (f), addr) != sizeof (f)) {
162 			warn("failed to read data from target");
163 			break;
164 		}
165 		mdb_iob_printf(mdb.m_out, "%e", f);
166 		addr += sizeof (f);
167 	}
168 	return (addr);
169 }
170 #endif
171 
172 /*ARGSUSED*/
173 static mdb_tgt_addr_t
fmt_plus(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)174 fmt_plus(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
175 {
176 	return (addr + cnt);
177 }
178 
179 /*ARGSUSED*/
180 static mdb_tgt_addr_t
fmt_minus(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)181 fmt_minus(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
182 {
183 	return (addr - cnt);
184 }
185 
186 /*ARGSUSED*/
187 static mdb_tgt_addr_t
fmt_carat(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)188 fmt_carat(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
189 {
190 	return (addr - (mdb.m_incr * cnt));
191 }
192 
193 /*ARGSUSED*/
194 static mdb_tgt_addr_t
fmt_nl(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)195 fmt_nl(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
196 {
197 	while (cnt-- != 0)
198 		mdb_iob_nl(mdb.m_out);
199 
200 	return (addr);
201 }
202 
203 /*ARGSUSED*/
204 static mdb_tgt_addr_t
fmt_ws(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)205 fmt_ws(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
206 {
207 	mdb_iob_ws(mdb.m_out, cnt);
208 	return (addr);
209 }
210 
211 /*ARGSUSED*/
212 static mdb_tgt_addr_t
fmt_tab(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)213 fmt_tab(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
214 {
215 	size_t ts = mdb_iob_gettabstop(mdb.m_out);
216 
217 	mdb_iob_tabstop(mdb.m_out, cnt);
218 	mdb_iob_tab(mdb.m_out);
219 	mdb_iob_tabstop(mdb.m_out, ts);
220 
221 	return (addr);
222 }
223 
224 static mdb_tgt_addr_t
fmt_rawstr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)225 fmt_rawstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
226 {
227 	uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
228 	char buf[BUFSIZ];
229 	ssize_t nbytes;
230 
231 	mdb_iob_clrflags(mdb.m_out, oflags);
232 
233 	for (; cnt-- != 0; addr++) {
234 		do {
235 			nbytes = mdb_tgt_readstr(t, as, buf, BUFSIZ, addr);
236 			if (nbytes > 0) {
237 				mdb_iob_puts(mdb.m_out, buf);
238 				addr += MIN(nbytes, BUFSIZ - 1);
239 			} else if (nbytes < 0) {
240 				warn("failed to read data from target");
241 				goto out;
242 			}
243 		} while (nbytes == BUFSIZ);
244 
245 		if (cnt != 0)
246 			mdb_iob_puts(mdb.m_out, "\\0");
247 	}
248 out:
249 	mdb_iob_setflags(mdb.m_out, oflags);
250 	return (addr);
251 }
252 
253 static mdb_tgt_addr_t
fmt_escstr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)254 fmt_escstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
255 {
256 	uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
257 	char buf[BUFSIZ];
258 	ssize_t nbytes;
259 	char *s;
260 
261 	mdb_iob_clrflags(mdb.m_out, oflags);
262 
263 	for (; cnt-- != 0; addr++) {
264 		do {
265 			nbytes = mdb_tgt_readstr(t, as, buf, BUFSIZ, addr);
266 			if (nbytes > 0) {
267 				s = strchr2esc(buf, strlen(buf));
268 				mdb_iob_puts(mdb.m_out, s);
269 				strfree(s);
270 				addr += MIN(nbytes, BUFSIZ - 1);
271 			} else if (nbytes < 0) {
272 				warn("failed to read data from target");
273 				goto out;
274 			}
275 		} while (nbytes == BUFSIZ);
276 
277 		if (cnt != 0)
278 			mdb_iob_puts(mdb.m_out, "\\0");
279 	}
280 out:
281 	mdb_iob_setflags(mdb.m_out, oflags);
282 	return (addr);
283 }
284 
285 static mdb_tgt_addr_t
fmt_escchr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)286 fmt_escchr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
287 {
288 	char *(*convert)(const char *, size_t);
289 	ssize_t nbytes;
290 	char *buf, *s;
291 
292 	if (mdb.m_flags & MDB_FL_ADB)
293 		convert = &strchr2adb;
294 	else
295 		convert = &strchr2esc;
296 
297 	buf = mdb_alloc(cnt + 1, UM_SLEEP);
298 	buf[cnt] = 0;
299 
300 	if ((nbytes = mdb_tgt_aread(t, as, buf, cnt, addr)) > 0) {
301 		s = convert(buf, nbytes);
302 		mdb_iob_puts(mdb.m_out, s);
303 		strfree(s);
304 		addr += nbytes;
305 	}
306 
307 	mdb_free(buf, cnt + 1);
308 	return (addr);
309 }
310 
311 static mdb_tgt_addr_t
fmt_swapshort(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)312 fmt_swapshort(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
313 {
314 	ushort_t x;
315 
316 	while (cnt-- != 0) {
317 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
318 			x = (x << 8) | (x >> 8);
319 			mdb_iob_printf(mdb.m_out, "%-8x", x);
320 			mdb_nv_set_value(mdb.m_rvalue, x);
321 			addr += sizeof (x);
322 		} else {
323 			warn("failed to read data from target");
324 			break;
325 		}
326 	}
327 	return (addr);
328 }
329 
330 static mdb_tgt_addr_t
fmt_swapint(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)331 fmt_swapint(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
332 {
333 	uint_t x;
334 
335 	while (cnt-- != 0) {
336 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
337 			x = ((x << 24) | ((x << 8) & 0xff0000) |
338 			    ((x >> 8) & 0xff00) | ((x >> 24) & 0xff));
339 			mdb_iob_printf(mdb.m_out, "%-16x", x);
340 			mdb_nv_set_value(mdb.m_rvalue, x);
341 			addr += sizeof (x);
342 		} else {
343 			warn("failed to read data from target");
344 			break;
345 		}
346 	}
347 	return (addr);
348 }
349 
350 static mdb_tgt_addr_t
fmt_time32(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)351 fmt_time32(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
352 {
353 	int32_t x;
354 
355 	while (cnt-- != 0) {
356 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
357 			mdb_iob_printf(mdb.m_out, "%-24Y", (time_t)x);
358 			mdb_nv_set_value(mdb.m_rvalue, x);
359 			addr += sizeof (x);
360 		} else {
361 			warn("failed to read data from target");
362 			break;
363 		}
364 	}
365 	return (addr);
366 }
367 
368 static mdb_tgt_addr_t
fmt_time64(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)369 fmt_time64(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
370 {
371 	int64_t x;
372 
373 	while (cnt-- != 0) {
374 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
375 			if ((time_t)x == x)
376 				mdb_iob_printf(mdb.m_out, "%-24Y", (time_t)x);
377 			else
378 				mdb_iob_printf(mdb.m_out, "%-24llR", x);
379 
380 			mdb_nv_set_value(mdb.m_rvalue, x);
381 			addr += sizeof (x);
382 		} else {
383 			warn("failed to read data from target");
384 			break;
385 		}
386 	}
387 	return (addr);
388 }
389 
390 static mdb_tgt_addr_t
fmt_sdbyte(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)391 fmt_sdbyte(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
392 {
393 	int8_t x;
394 
395 	while (cnt-- != 0) {
396 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
397 			mdb_iob_printf(mdb.m_out, "%-8d", (int32_t)x);
398 			mdb_nv_set_value(mdb.m_rvalue, (uint8_t)x);
399 			addr += sizeof (x);
400 		} else {
401 			warn("failed to read data from target");
402 			break;
403 		}
404 	}
405 	return (addr);
406 }
407 
408 static mdb_tgt_addr_t
fmt_instr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)409 fmt_instr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
410 {
411 	char buf[BUFSIZ];
412 	uintptr_t naddr;
413 
414 	if (as == MDB_TGT_AS_VIRT)
415 		as = MDB_TGT_AS_VIRT_I;
416 
417 	while (cnt-- != 0) {
418 		naddr = mdb_dis_ins2str(mdb.m_disasm, t, as,
419 		    buf, sizeof (buf), addr);
420 		if (naddr == addr)
421 			return (addr); /* If we didn't move, we failed */
422 		mdb_iob_printf(mdb.m_out, "%s\n", buf);
423 		addr = naddr;
424 	}
425 	return (addr);
426 }
427 
428 static mdb_tgt_addr_t
fmt_dotinstr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)429 fmt_dotinstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
430 {
431 	uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
432 
433 	char buf[BUFSIZ];
434 	uintptr_t naddr;
435 	uint32_t i;
436 
437 	if (as == MDB_TGT_AS_VIRT)
438 		as = MDB_TGT_AS_VIRT_I;
439 
440 	for (mdb_iob_clrflags(mdb.m_out, oflags); cnt-- != 0; addr = naddr) {
441 		if (mdb_tgt_aread(t, as, &i, sizeof (i), addr) != sizeof (i)) {
442 			warn("failed to read data from target");
443 			break; /* Fail if we can't read instruction */
444 		}
445 		naddr = mdb_dis_ins2str(mdb.m_disasm, t, as,
446 		    buf, sizeof (buf), addr);
447 		if (naddr == addr)
448 			break; /* Fail if we didn't advance */
449 		mdb_iob_printf(mdb.m_out, "%lx %x: %s\n", (long)addr, i, buf);
450 	}
451 
452 	mdb_iob_setflags(mdb.m_out, oflags);
453 	return (addr);
454 }
455 
456 static mdb_tgt_addr_t
fmt_binary(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)457 fmt_binary(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
458 {
459 	uint64_t x;
460 	const char *fmts[] = { "%-64s", "%-65s" };
461 	const uint64_t mask = 0x8000000000000000ull;
462 
463 	while (cnt-- != 0) {
464 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
465 			mdb_iob_printf(mdb.m_out, fmts[(x & mask) != 0],
466 			    numtostr(x, 2, NTOS_UNSIGNED));
467 			mdb_nv_set_value(mdb.m_rvalue, x);
468 			addr += sizeof (x);
469 		} else {
470 			warn("failed to read data from target");
471 			break;
472 		}
473 	}
474 	return (addr);
475 }
476 
477 static mdb_tgt_addr_t
fmt_jazzed(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)478 fmt_jazzed(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
479 {
480 	uint64_t x;
481 	char buf[256];
482 
483 	while (cnt-- != 0) {
484 		boolean_t header = B_TRUE;
485 
486 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) != sizeof (x)) {
487 			warn("failed to read data from target");
488 			break;
489 		}
490 
491 		mdb_nv_set_value(mdb.m_rvalue, x);
492 		addr += sizeof (x);
493 
494 		mdb_iob_printf(mdb.m_out, "%s\n",
495 		    numtostr(x, 2, NTOS_UNSIGNED));
496 
497 		while (x != 0) {
498 			int b = 63, forearm;
499 			int i = 0, highbit;
500 
501 			/*
502 			 * Find the high bit...
503 			 */
504 			while (!(x & (1ULL << b)))
505 				b--;
506 
507 			highbit = b;
508 
509 			/*
510 			 * ...and iterate over the remaining bits, putting
511 			 * the upper arm in our buffer for any set bit (and
512 			 * a space otherwise).
513 			 */
514 			while (x & ((1ULL << b) - 1)) {
515 				buf[i++] = x & (1ULL << b) ? '|' : ' ';
516 				b--;
517 			}
518 
519 			/*
520 			 * If this is the header line, print the upper arm
521 			 * for the lowest set bit and continue...
522 			 */
523 			if (header) {
524 				header = B_FALSE;
525 				buf[i] = '\0';
526 				mdb_iob_printf(mdb.m_out, "%s|\n", buf);
527 				continue;
528 			}
529 
530 			/*
531 			 * ...otherwise, put the elbow and forearm into our
532 			 * buffer, and print it.
533 			 */
534 			buf[i++] = '+';
535 
536 			for (forearm = b; forearm > -2; forearm--)
537 				buf[i++] = '-';
538 
539 			buf[i] = '\0';
540 			mdb_iob_printf(mdb.m_out, "%s bit %d %smask 0x%0*llx\n",
541 			    buf, b, b < 10 && highbit >= 10 ? " " : "",
542 			    (highbit / 4) + 1, 1ULL << b);
543 
544 			/*
545 			 * Finally, clear the lowest set bit and continue.
546 			 */
547 			x &= ~(1ULL << b);
548 		}
549 	}
550 
551 	return (addr);
552 }
553 
554 static mdb_tgt_addr_t
fmt_hex64(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)555 fmt_hex64(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
556 {
557 	const char *fmts[] = { "%-16llx", "%-17llx" };
558 	const uint64_t mask = 0xf000000000000000ull;
559 	uint64_t x;
560 
561 	while (cnt-- != 0) {
562 		if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
563 			mdb_iob_printf(mdb.m_out, fmts[(x & mask) != 0], x);
564 			mdb_nv_set_value(mdb.m_rvalue, x);
565 			addr += sizeof (x);
566 		} else {
567 			warn("failed to read data from target");
568 			break;
569 		}
570 	}
571 	return (addr);
572 }
573 
574 static const mdb_fmt_desc_t fmttab[] = {
575 	{ FMT_NONE, NULL, NULL, 0 },				/* 0 = NUL */
576 	{ FMT_NONE, NULL, NULL, 0 },				/* 1 = SOH */
577 	{ FMT_NONE, NULL, NULL, 0 },				/* 2 = STX */
578 	{ FMT_NONE, NULL, NULL, 0 },				/* 3 = ETX */
579 	{ FMT_NONE, NULL, NULL, 0 },				/* 4 = EOT */
580 	{ FMT_NONE, NULL, NULL, 0 },				/* 5 = ENQ */
581 	{ FMT_NONE, NULL, NULL, 0 },				/* 6 = ACK */
582 	{ FMT_NONE, NULL, NULL, 0 },				/* 7 = BEL */
583 	{ FMT_NONE, NULL, NULL, 0 },				/* 8 = BS */
584 	{ FMT_NONE, NULL, NULL, 0 },				/* 9 = \t */
585 	{ FMT_NONE, NULL, NULL, 0 },				/* 10 = \n */
586 	{ FMT_NONE, NULL, NULL, 0 },				/* 11 = VT */
587 	{ FMT_NONE, NULL, NULL, 0 },				/* 12 = FF */
588 	{ FMT_NONE, NULL, NULL, 0 },				/* 13 = \r */
589 	{ FMT_NONE, NULL, NULL, 0 },				/* 14 = SO */
590 	{ FMT_NONE, NULL, NULL, 0 },				/* 15 = SI */
591 	{ FMT_NONE, NULL, NULL, 0 },				/* 16 = DLE */
592 	{ FMT_NONE, NULL, NULL, 0 },				/* 17 = DC1 */
593 	{ FMT_NONE, NULL, NULL, 0 },				/* 18 = DC2 */
594 	{ FMT_NONE, NULL, NULL, 0 },				/* 19 = DC3 */
595 	{ FMT_NONE, NULL, NULL, 0 },				/* 20 = DC4 */
596 	{ FMT_NONE, NULL, NULL, 0 },				/* 21 = NAK */
597 	{ FMT_NONE, NULL, NULL, 0 },				/* 22 = EYC */
598 	{ FMT_NONE, NULL, NULL, 0 },				/* 23 = ETB */
599 	{ FMT_NONE, NULL, NULL, 0 },				/* 24 = CAN */
600 	{ FMT_NONE, NULL, NULL, 0 },				/* 25 = EM */
601 	{ FMT_NONE, NULL, NULL, 0 },				/* 26 = SUB */
602 	{ FMT_NONE, NULL, NULL, 0 },				/* 27 = ESC */
603 	{ FMT_NONE, NULL, NULL, 0 },				/* 28 = FS */
604 	{ FMT_NONE, NULL, NULL, 0 },				/* 29 = GS */
605 	{ FMT_NONE, NULL, NULL, 0 },				/* 30 = RS */
606 	{ FMT_NONE, NULL, NULL, 0 },				/* 31 = US */
607 	{ FMT_NONE, NULL, NULL, 0 },				/* 32 = SPACE */
608 	{ FMT_NONE, NULL, NULL, 0 },				/* 33 = ! */
609 	{ FMT_NONE, NULL, NULL, 0 },				/* 34 = " */
610 	{ FMT_NONE, NULL, NULL, 0 },				/* 35 = # */
611 	{ FMT_NONE, NULL, NULL, 0 },				/* 36 = $ */
612 	{ FMT_NONE, NULL, NULL, 0 },				/* 37 = % */
613 	{ FMT_NONE, NULL, NULL, 0 },				/* 38 = & */
614 	{ FMT_NONE, NULL, NULL, 0 },				/* 39 = ' */
615 	{ FMT_NONE, NULL, NULL, 0 },				/* 40 = ( */
616 	{ FMT_NONE, NULL, NULL, 0 },				/* 41 = ) */
617 	{ FMT_NONE, NULL, NULL, 0 },				/* 42 = * */
618 	{ FMT_FUNC, FUNCP(fmt_plus), help_plus, 0 },		/* 43 = + */
619 	{ FMT_NONE, NULL, NULL, 0 },				/* 44 = , */
620 	{ FMT_FUNC, FUNCP(fmt_minus), help_minus, 0 },		/* 45 = - */
621 	{ FMT_NONE, NULL, NULL, 0 },				/* 46 = . */
622 	{ FMT_NONE, NULL, NULL, 0 },				/* 47 = / */
623 	{ FMT_NONE, NULL, NULL, 0 },				/* 48 = 0 */
624 	{ FMT_NONE, NULL, NULL, 0 },				/* 49 = 1 */
625 	{ FMT_NONE, NULL, NULL, 0 },				/* 50 = 2 */
626 	{ FMT_NONE, NULL, NULL, 0 },				/* 51 = 3 */
627 	{ FMT_NONE, NULL, NULL, 0 },				/* 52 = 4 */
628 	{ FMT_NONE, NULL, NULL, 0 },				/* 53 = 5 */
629 	{ FMT_NONE, NULL, NULL, 0 },				/* 54 = 6 */
630 	{ FMT_NONE, NULL, NULL, 0 },				/* 55 = 7 */
631 	{ FMT_NONE, NULL, NULL, 0 },				/* 56 = 8 */
632 	{ FMT_NONE, NULL, NULL, 0 },				/* 57 = 9 */
633 	{ FMT_NONE, NULL, NULL, 0 },				/* 58 = : */
634 	{ FMT_NONE, NULL, NULL, 0 },				/* 59 = ; */
635 	{ FMT_NONE, NULL, NULL, 0 },				/* 60 = < */
636 	{ FMT_NONE, NULL, NULL, 0 },				/* 61 = = */
637 	{ FMT_NONE, NULL, NULL, 0 },				/* 62 = > */
638 	{ FMT_NONE, NULL, NULL, 0 },				/* 63 = ? */
639 	{ FMT_NONE, NULL, NULL, 0 },				/* 64 = @ */
640 	{ FMT_NONE, NULL, NULL, 0 },				/* 65 = A */
641 	{ FMT_PRINTF, "%-8x", NULL, 1 },			/* 66 = B */
642 	{ FMT_FUNC, FUNCP(fmt_escchr), help_escchr, 1 },	/* 67 = C */
643 	{ FMT_PRINTF, "%-16d", NULL, 4 },			/* 68 = D */
644 	{ FMT_PRINTF, "%-21llu", NULL, 8 },			/* 69 = E */
645 #ifdef _KMDB
646 	{ FMT_NONE, NULL, NULL, 0 },				/* 70 = F */
647 #else
648 	{ FMT_PRINTF, "%g", NULL, sizeof (double), B_TRUE },	/* 70 = F */
649 #endif
650 	{ FMT_PRINTF, "%-23llo", NULL, 8 },			/* 71 = G */
651 	{ FMT_FUNC, FUNCP(fmt_swapint), help_swapint, 4 },	/* 72 = H */
652 	{ FMT_FUNC, FUNCP(fmt_dotinstr), help_dotinstr, 0 },	/* 73 = I */
653 	{ FMT_FUNC, FUNCP(fmt_hex64), help_hex64, 8 },		/* 74 = J */
654 #ifdef _LP64
655 	{ FMT_FUNC, FUNCP(fmt_hex64), help_uintptr, 8 },	/* 75 = K (J) */
656 #else
657 	{ FMT_PRINTF, "%-16x", help_uintptr, 4 },		/* 75 = K (X) */
658 #endif
659 	{ FMT_MATCH, NULL, help_match32, 4 },			/* 76 = L */
660 	{ FMT_MATCH, NULL, help_match64, 8 },			/* 77 = M */
661 	{ FMT_FUNC, FUNCP(fmt_nl), help_nl, SZ_NONE },		/* 78 = N */
662 	{ FMT_PRINTF, "%-#16o", NULL, 4 },			/* 79 = O */
663 	{ FMT_PRINTF, "%-19a", NULL, sizeof (uintptr_t) },	/* 80 = P */
664 	{ FMT_PRINTF, "%-#16q", NULL, 4 },			/* 81 = Q */
665 	{ FMT_FUNC, FUNCP(fmt_binary), help_binary, 8 },	/* 82 = R */
666 	{ FMT_FUNC, FUNCP(fmt_escstr), help_escstr, 0 },	/* 83 = S */
667 	{ FMT_FUNC, FUNCP(fmt_tab), help_tab, SZ_NONE },	/* 84 = T */
668 	{ FMT_PRINTF, "%-16u", NULL, 4 },			/* 85 = U */
669 	{ FMT_PRINTF, "%-8u", NULL, 1 },			/* 86 = V */
670 	{ FMT_PRINTF|FMT_WRITE, "%-16r", NULL, 4 },		/* 87 = W */
671 	{ FMT_PRINTF, "%-16x", NULL, 4 },			/* 88 = X */
672 	{ FMT_FUNC, FUNCP(fmt_time32), help_time32, 4 },	/* 89 = Y */
673 	{ FMT_FUNC|FMT_WRITE, FUNCP(fmt_hex64), help_hex64, 8 }, /* 90 = Z */
674 	{ FMT_NONE, NULL, NULL, 0 },				/* 91 = [ */
675 	{ FMT_NONE, NULL, NULL, 0 },				/* 92 = \ */
676 	{ FMT_NONE, NULL, NULL, 0 },				/* 93 = ] */
677 	{ FMT_FUNC, FUNCP(fmt_carat), help_carat, 0 },		/* 94 = ^ */
678 	{ FMT_NONE, NULL, NULL, 0 },				/* 95 = _ */
679 	{ FMT_NONE, NULL, NULL, 0 },				/* 96 = ` */
680 	{ FMT_FUNC, FUNCP(fmt_dot), help_dot, SZ_NONE },	/* 97 = a */
681 	{ FMT_PRINTF, "%-#8o", NULL, 1 },			/* 98 = b */
682 	{ FMT_PRINTF, "%c", NULL, 1 },				/* 99 = c */
683 	{ FMT_PRINTF, "%-8hd", NULL, 2 },			/* 100 = d */
684 	{ FMT_PRINTF, "%-21lld", NULL, 8 },			/* 101 = e */
685 #ifdef _KMDB
686 	{ FMT_NONE, NULL, NULL, 0 },				/* 102 = f */
687 #else
688 	{ FMT_FUNC, FUNCP(fmt_float), help_f, sizeof (float),
689 	    B_TRUE },						/* 102 = f */
690 #endif
691 	{ FMT_PRINTF, "%-24llq", NULL, 8 },			/* 103 = g */
692 	{ FMT_FUNC, FUNCP(fmt_swapshort), help_swapshort, 2 },	/* 104 = h */
693 	{ FMT_FUNC, FUNCP(fmt_instr), help_instr, 0 },		/* 105 = i */
694 	{ FMT_FUNC|FMT_NOAUTOWRAP,
695 	    FUNCP(fmt_jazzed), help_jazzed, 8 },		/* 106 = j */
696 	{ FMT_NONE, NULL, NULL, 0 },				/* 107 = k */
697 	{ FMT_MATCH, NULL, help_match16, 2 },			/* 108 = l */
698 	{ FMT_NONE, NULL, NULL, 0 },				/* 109 = m */
699 	{ FMT_FUNC, FUNCP(fmt_nl), help_nl, SZ_NONE },		/* 110 = n */
700 	{ FMT_PRINTF, "%-#8ho", NULL, 2 },			/* 111 = o */
701 	{ FMT_PRINTF, "%-19a", NULL, sizeof (uintptr_t) },	/* 112 = p */
702 	{ FMT_PRINTF, "%-#8hq", NULL, 2 },			/* 113 = q */
703 	{ FMT_FUNC, FUNCP(fmt_ws), help_ws, SZ_NONE },		/* 114 = r */
704 	{ FMT_FUNC, FUNCP(fmt_rawstr), help_rawstr, 0 },	/* 115 = s */
705 	{ FMT_FUNC, FUNCP(fmt_tab), help_tab, SZ_NONE },	/* 116 = t */
706 	{ FMT_PRINTF, "%-8hu", NULL, 2 },			/* 117 = u */
707 	{ FMT_FUNC|FMT_WRITE, FUNCP(fmt_sdbyte), help_sdbyte, 1 }, /* 118 = v */
708 	{ FMT_PRINTF|FMT_WRITE, "%-8hr", NULL, 2 },		/* 119 = w */
709 	{ FMT_PRINTF, "%-8hx", NULL, 2 },			/* 120 = x */
710 	{ FMT_FUNC, FUNCP(fmt_time64), help_time64, 8 },	/* 121 = y */
711 	{ FMT_WRITE, NULL, help_ctf, 0 },			/* 122 = z */
712 };
713 
714 mdb_tgt_addr_t
mdb_fmt_print(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt,char fmt)715 mdb_fmt_print(mdb_tgt_t *t, mdb_tgt_as_t as,
716     mdb_tgt_addr_t addr, size_t cnt, char fmt)
717 {
718 	const mdb_fmt_desc_t *fp = &fmttab[fmt];
719 	mdb_fmt_func_f *funcp;
720 	uintmax_t rvalue;
721 	void *buf;
722 	uint_t oflags = mdb.m_flags;
723 
724 	union {
725 		uint64_t i8;
726 		uint32_t i4;
727 		uint16_t i2;
728 		uint8_t i1;
729 		double d;
730 	} u;
731 
732 	if (fmt < 0 || fmt > (sizeof (fmttab) / sizeof (fmttab[0]))) {
733 		warn("invalid format character -- '%c'\n", fmt);
734 		return (addr);
735 	}
736 
737 	if (!(fp->f_type & FMT_NOAUTOWRAP)) {
738 		/*
739 		 * Unless a format has explicitly opted out, we force autowrap
740 		 * for the duration of mdb_fmt_print().
741 		 */
742 		mdb_iob_set_autowrap(mdb.m_out);
743 	}
744 
745 	switch (FMT_TYPE(fp->f_type)) {
746 	case FMT_FUNC:
747 		funcp = (mdb_fmt_func_f *)fp->f_ptr;
748 		addr = funcp(t, as, addr, cnt);
749 		break;
750 
751 	case FMT_PRINTF:
752 		switch (fp->f_size) {
753 		case 1:
754 			buf = &u.i1;
755 			break;
756 		case 2:
757 			buf = &u.i2;
758 			break;
759 		case 4:
760 			buf = &u.i4;
761 			break;
762 		case 8:
763 			buf = &u.i8;
764 			break;
765 		default:
766 			fail("format %c is defined using illegal size\n", fmt);
767 		}
768 
769 		if (fp->f_float == B_TRUE) {
770 			if (fp->f_size != 8) {
771 				fail("format %c is using illegal fp size\n",
772 				    fmt);
773 			}
774 
775 			buf = &u.d;
776 		}
777 
778 		while (cnt-- != 0) {
779 			if (mdb_tgt_aread(t, as, buf, fp->f_size, addr) !=
780 			    fp->f_size) {
781 				warn("failed to read data from target");
782 				return (addr);
783 			}
784 
785 			switch (fp->f_size) {
786 			case 1:
787 				mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i1);
788 				rvalue = u.i1;
789 				break;
790 			case 2:
791 				mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i2);
792 				rvalue = u.i2;
793 				break;
794 			case 4:
795 				mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i4);
796 				rvalue = u.i4;
797 				break;
798 			case 8:
799 				if (fp->f_float) {
800 					mdb_iob_printf(mdb.m_out, fp->f_ptr,
801 					    u.d);
802 				} else {
803 					mdb_iob_printf(mdb.m_out, fp->f_ptr,
804 					    u.i8);
805 				}
806 				rvalue = u.i8;
807 				break;
808 			default:
809 				rvalue = 0;
810 				break;
811 			}
812 
813 			mdb_nv_set_value(mdb.m_rvalue, rvalue);
814 			addr += fp->f_size;
815 		}
816 		break;
817 
818 	default:
819 		warn("invalid format character -- '%c'\n", fmt);
820 	}
821 
822 	mdb.m_flags = oflags;
823 
824 	return (addr);
825 }
826 
827 /*ARGSUSED*/
828 int
cmd_formats(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)829 cmd_formats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
830 {
831 	const mdb_fmt_desc_t *fp = &fmttab[0];
832 	int i;
833 	const char *write;
834 
835 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
836 		return (DCMD_USAGE);
837 
838 	for (i = 0; i < (sizeof (fmttab) / sizeof (fmttab[0])); i++, fp++) {
839 		if (fp->f_type == FMT_NONE)
840 			continue;
841 
842 		write = (fp->f_type & FMT_WRITE) ? "write " : "";
843 
844 		if (fp->f_type & FMT_FUNC)
845 			mdb_printf("%c - %s%s", i, write, fp->f_help);
846 		else if (fp->f_type & FMT_MATCH)
847 			mdb_printf("%c - match %s", i, fp->f_help);
848 		else if (fp->f_help != NULL)
849 			mdb_printf("%c - %s%s", i, write, fp->f_help);
850 		else
851 			mdb_printf("%c - %s%s", i, write,
852 			    mdb_iob_format2str(fp->f_ptr));
853 
854 		switch (fp->f_size) {
855 		case SZ_NONE:
856 			mdb_printf("\n");
857 			break;
858 		case 0:
859 			mdb_printf(" (variable size)\n");
860 			break;
861 		case 1:
862 			mdb_printf(" (1 byte)\n");
863 			break;
864 		default:
865 			mdb_printf(" (%lu bytes)\n", fp->f_size);
866 		}
867 	}
868 
869 	return (DCMD_OK);
870 }
871