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 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
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
86 #define FMT_TYPE(x) ((x) & 0x7) /* Excludes modifying flags (FMT_WRITE) */
87
88 typedef struct mdb_fmt_desc {
89 int f_type; /* Type of format (see above) */
90 void *f_ptr; /* Data pointer (see above) */
91 const char *f_help; /* Additional help string */
92 size_t f_size; /* Size of type in bytes, or SZ_NONE */
93 } mdb_fmt_desc_t;
94
95 static const char help_plus[] = "increment dot by the count";
96 static const char help_minus[] = "decrement dot by the count";
97 static const char help_escchr[] = "character using C character notation";
98 static const char help_swapint[] = "swap bytes and shorts";
99 static const char help_dotinstr[] = "address and disassembled instruction";
100 static const char help_instr[] = "disassembled instruction";
101 static const char help_escstr[] = "string using C string notation";
102 static const char help_time32[] = "decoded time32_t";
103 static const char help_carat[] = "decrement dot by increment * count";
104 static const char help_dot[] = "dot as symbol+offset";
105 #ifndef _KMDB
106 static const char help_f[] = "float";
107 #endif
108 static const char help_swapshort[] = "swap bytes";
109 static const char help_nl[] = "newline";
110 static const char help_ws[] = "whitespace";
111 static const char help_rawstr[] = "raw string";
112 static const char help_tab[] = "horizontal tab";
113 static const char help_sdbyte[] = "decimal signed int";
114 static const char help_time64[] = "decoded time64_t";
115 static const char help_binary[] = "binary unsigned long long";
116 static const char help_hex64[] = "hexadecimal long long";
117 static const char help_match32[] = "int";
118 static const char help_match64[] = "long long";
119 static const char help_match16[] = "short";
120 static const char help_uintptr[] = "hexadecimal uintptr_t";
121
122 /*ARGSUSED*/
123 static mdb_tgt_addr_t
fmt_dot(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)124 fmt_dot(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
125 {
126 uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
127 char buf[24];
128
129 mdb_iob_clrflags(mdb.m_out, oflags);
130
131 if (mdb.m_flags & MDB_FL_PSYM) {
132 while (cnt-- != 0)
133 mdb_iob_printf(mdb.m_out, "%-#16lla%16T", addr);
134 } else {
135 (void) mdb_iob_snprintf(buf, sizeof (buf),
136 "%#llx:", (u_longlong_t)addr);
137 while (cnt-- != 0)
138 mdb_iob_printf(mdb.m_out, "%-16s%16T", buf);
139 }
140
141 mdb_iob_setflags(mdb.m_out, oflags);
142 mdb_nv_set_value(mdb.m_rvalue, addr);
143 return (addr);
144 }
145
146 #ifndef _KMDB
147 static mdb_tgt_addr_t
fmt_float(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)148 fmt_float(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
149 {
150 float f;
151 /*
152 * We need to handle float as a special case because we need it to be
153 * promoted to a double by virtue of appearing as a parameter, and all
154 * our generic format handling below is based on integer types.
155 */
156 while (cnt-- != 0) {
157 if (mdb_tgt_aread(t, as, &f, sizeof (f), addr) != sizeof (f)) {
158 warn("failed to read data from target");
159 break;
160 }
161 mdb_iob_printf(mdb.m_out, "%e", f);
162 addr += sizeof (f);
163 }
164 return (addr);
165 }
166 #endif
167
168 /*ARGSUSED*/
169 static mdb_tgt_addr_t
fmt_plus(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)170 fmt_plus(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
171 {
172 return (addr + cnt);
173 }
174
175 /*ARGSUSED*/
176 static mdb_tgt_addr_t
fmt_minus(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)177 fmt_minus(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
178 {
179 return (addr - cnt);
180 }
181
182 /*ARGSUSED*/
183 static mdb_tgt_addr_t
fmt_carat(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)184 fmt_carat(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
185 {
186 return (addr - (mdb.m_incr * cnt));
187 }
188
189 /*ARGSUSED*/
190 static mdb_tgt_addr_t
fmt_nl(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)191 fmt_nl(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
192 {
193 while (cnt-- != 0)
194 mdb_iob_nl(mdb.m_out);
195
196 return (addr);
197 }
198
199 /*ARGSUSED*/
200 static mdb_tgt_addr_t
fmt_ws(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)201 fmt_ws(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
202 {
203 mdb_iob_ws(mdb.m_out, cnt);
204 return (addr);
205 }
206
207 /*ARGSUSED*/
208 static mdb_tgt_addr_t
fmt_tab(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)209 fmt_tab(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
210 {
211 size_t ts = mdb_iob_gettabstop(mdb.m_out);
212
213 mdb_iob_tabstop(mdb.m_out, cnt);
214 mdb_iob_tab(mdb.m_out);
215 mdb_iob_tabstop(mdb.m_out, ts);
216
217 return (addr);
218 }
219
220 static mdb_tgt_addr_t
fmt_rawstr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)221 fmt_rawstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
222 {
223 uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
224 char buf[BUFSIZ];
225 ssize_t nbytes;
226
227 mdb_iob_clrflags(mdb.m_out, oflags);
228
229 for (; cnt-- != 0; addr++) {
230 do {
231 nbytes = mdb_tgt_readstr(t, as, buf, BUFSIZ, addr);
232 if (nbytes > 0) {
233 mdb_iob_puts(mdb.m_out, buf);
234 addr += MIN(nbytes, BUFSIZ - 1);
235 } else if (nbytes < 0) {
236 warn("failed to read data from target");
237 goto out;
238 }
239 } while (nbytes == BUFSIZ);
240
241 if (cnt != 0)
242 mdb_iob_puts(mdb.m_out, "\\0");
243 }
244 out:
245 mdb_iob_setflags(mdb.m_out, oflags);
246 return (addr);
247 }
248
249 static mdb_tgt_addr_t
fmt_escstr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)250 fmt_escstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
251 {
252 uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
253 char buf[BUFSIZ];
254 ssize_t nbytes;
255 char *s;
256
257 mdb_iob_clrflags(mdb.m_out, oflags);
258
259 for (; cnt-- != 0; addr++) {
260 do {
261 nbytes = mdb_tgt_readstr(t, as, buf, BUFSIZ, addr);
262 if (nbytes > 0) {
263 s = strchr2esc(buf, strlen(buf));
264 mdb_iob_puts(mdb.m_out, s);
265 strfree(s);
266 addr += MIN(nbytes, BUFSIZ - 1);
267 } else if (nbytes < 0) {
268 warn("failed to read data from target");
269 goto out;
270 }
271 } while (nbytes == BUFSIZ);
272
273 if (cnt != 0)
274 mdb_iob_puts(mdb.m_out, "\\0");
275 }
276 out:
277 mdb_iob_setflags(mdb.m_out, oflags);
278 return (addr);
279 }
280
281 static mdb_tgt_addr_t
fmt_escchr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)282 fmt_escchr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
283 {
284 char *(*convert)(const char *, size_t);
285 ssize_t nbytes;
286 char *buf, *s;
287
288 if (mdb.m_flags & MDB_FL_ADB)
289 convert = &strchr2adb;
290 else
291 convert = &strchr2esc;
292
293 buf = mdb_alloc(cnt + 1, UM_SLEEP);
294 buf[cnt] = 0;
295
296 if ((nbytes = mdb_tgt_aread(t, as, buf, cnt, addr)) > 0) {
297 s = convert(buf, nbytes);
298 mdb_iob_puts(mdb.m_out, s);
299 strfree(s);
300 addr += nbytes;
301 }
302
303 mdb_free(buf, cnt + 1);
304 return (addr);
305 }
306
307 static mdb_tgt_addr_t
fmt_swapshort(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)308 fmt_swapshort(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
309 {
310 ushort_t x;
311
312 while (cnt-- != 0) {
313 if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
314 x = (x << 8) | (x >> 8);
315 mdb_iob_printf(mdb.m_out, "%-8x", x);
316 mdb_nv_set_value(mdb.m_rvalue, x);
317 addr += sizeof (x);
318 } else {
319 warn("failed to read data from target");
320 break;
321 }
322 }
323 return (addr);
324 }
325
326 static mdb_tgt_addr_t
fmt_swapint(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)327 fmt_swapint(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
328 {
329 uint_t x;
330
331 while (cnt-- != 0) {
332 if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
333 x = ((x << 24) | ((x << 8) & 0xff0000) |
334 ((x >> 8) & 0xff00) | ((x >> 24) & 0xff));
335 mdb_iob_printf(mdb.m_out, "%-16x", x);
336 mdb_nv_set_value(mdb.m_rvalue, x);
337 addr += sizeof (x);
338 } else {
339 warn("failed to read data from target");
340 break;
341 }
342 }
343 return (addr);
344 }
345
346 static mdb_tgt_addr_t
fmt_time32(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)347 fmt_time32(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
348 {
349 int32_t x;
350
351 while (cnt-- != 0) {
352 if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
353 mdb_iob_printf(mdb.m_out, "%-24Y", (time_t)x);
354 mdb_nv_set_value(mdb.m_rvalue, x);
355 addr += sizeof (x);
356 } else {
357 warn("failed to read data from target");
358 break;
359 }
360 }
361 return (addr);
362 }
363
364 static mdb_tgt_addr_t
fmt_time64(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)365 fmt_time64(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
366 {
367 int64_t x;
368
369 while (cnt-- != 0) {
370 if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
371 if ((time_t)x == x)
372 mdb_iob_printf(mdb.m_out, "%-24Y", (time_t)x);
373 else
374 mdb_iob_printf(mdb.m_out, "%-24llR", x);
375
376 mdb_nv_set_value(mdb.m_rvalue, x);
377 addr += sizeof (x);
378 } else {
379 warn("failed to read data from target");
380 break;
381 }
382 }
383 return (addr);
384 }
385
386 static mdb_tgt_addr_t
fmt_sdbyte(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)387 fmt_sdbyte(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
388 {
389 int8_t x;
390
391 while (cnt-- != 0) {
392 if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
393 mdb_iob_printf(mdb.m_out, "%-8d", (int32_t)x);
394 mdb_nv_set_value(mdb.m_rvalue, (uint8_t)x);
395 addr += sizeof (x);
396 } else {
397 warn("failed to read data from target");
398 break;
399 }
400 }
401 return (addr);
402 }
403
404 static mdb_tgt_addr_t
fmt_instr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)405 fmt_instr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
406 {
407 char buf[BUFSIZ];
408 uintptr_t naddr;
409
410 while (cnt-- != 0) {
411 naddr = mdb_dis_ins2str(mdb.m_disasm, t, as,
412 buf, sizeof (buf), addr);
413 if (naddr == addr)
414 return (addr); /* If we didn't move, we failed */
415 mdb_iob_printf(mdb.m_out, "%s\n", buf);
416 addr = naddr;
417 }
418 return (addr);
419 }
420
421 static mdb_tgt_addr_t
fmt_dotinstr(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)422 fmt_dotinstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
423 {
424 uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT;
425
426 char buf[BUFSIZ];
427 uintptr_t naddr;
428 uint32_t i;
429
430 for (mdb_iob_clrflags(mdb.m_out, oflags); cnt-- != 0; addr = naddr) {
431 if (mdb_tgt_aread(t, as, &i, sizeof (i), addr) != sizeof (i)) {
432 warn("failed to read data from target");
433 break; /* Fail if we can't read instruction */
434 }
435 naddr = mdb_dis_ins2str(mdb.m_disasm, t, as,
436 buf, sizeof (buf), addr);
437 if (naddr == addr)
438 break; /* Fail if we didn't advance */
439 mdb_iob_printf(mdb.m_out, "%lx %x: %s\n", (long)addr, i, buf);
440 }
441
442 mdb_iob_setflags(mdb.m_out, oflags);
443 return (addr);
444 }
445
446 static mdb_tgt_addr_t
fmt_binary(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)447 fmt_binary(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
448 {
449 uint64_t x;
450
451 while (cnt-- != 0) {
452 if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
453 mdb_iob_printf(mdb.m_out, "%-64s",
454 numtostr(x, 2, NTOS_UNSIGNED));
455 mdb_nv_set_value(mdb.m_rvalue, x);
456 addr += sizeof (x);
457 } else {
458 warn("failed to read data from target");
459 break;
460 }
461 }
462 return (addr);
463 }
464
465 static mdb_tgt_addr_t
fmt_hex64(mdb_tgt_t * t,mdb_tgt_as_t as,mdb_tgt_addr_t addr,size_t cnt)466 fmt_hex64(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
467 {
468 const char *fmts[] = { "%-16llx", "%-17llx" };
469 const uint64_t mask = 0xf000000000000000ull;
470 uint64_t x;
471
472 while (cnt-- != 0) {
473 if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
474 mdb_iob_printf(mdb.m_out, fmts[(x & mask) != 0], x);
475 mdb_nv_set_value(mdb.m_rvalue, x);
476 addr += sizeof (x);
477 } else {
478 warn("failed to read data from target");
479 break;
480 }
481 }
482 return (addr);
483 }
484
485 static const mdb_fmt_desc_t fmttab[] = {
486 { FMT_NONE, NULL, NULL, 0 }, /* 0 = NUL */
487 { FMT_NONE, NULL, NULL, 0 }, /* 1 = SOH */
488 { FMT_NONE, NULL, NULL, 0 }, /* 2 = STX */
489 { FMT_NONE, NULL, NULL, 0 }, /* 3 = ETX */
490 { FMT_NONE, NULL, NULL, 0 }, /* 4 = EOT */
491 { FMT_NONE, NULL, NULL, 0 }, /* 5 = ENQ */
492 { FMT_NONE, NULL, NULL, 0 }, /* 6 = ACK */
493 { FMT_NONE, NULL, NULL, 0 }, /* 7 = BEL */
494 { FMT_NONE, NULL, NULL, 0 }, /* 8 = BS */
495 { FMT_NONE, NULL, NULL, 0 }, /* 9 = \t */
496 { FMT_NONE, NULL, NULL, 0 }, /* 10 = \n */
497 { FMT_NONE, NULL, NULL, 0 }, /* 11 = VT */
498 { FMT_NONE, NULL, NULL, 0 }, /* 12 = FF */
499 { FMT_NONE, NULL, NULL, 0 }, /* 13 = \r */
500 { FMT_NONE, NULL, NULL, 0 }, /* 14 = SO */
501 { FMT_NONE, NULL, NULL, 0 }, /* 15 = SI */
502 { FMT_NONE, NULL, NULL, 0 }, /* 16 = DLE */
503 { FMT_NONE, NULL, NULL, 0 }, /* 17 = DC1 */
504 { FMT_NONE, NULL, NULL, 0 }, /* 18 = DC2 */
505 { FMT_NONE, NULL, NULL, 0 }, /* 19 = DC3 */
506 { FMT_NONE, NULL, NULL, 0 }, /* 20 = DC4 */
507 { FMT_NONE, NULL, NULL, 0 }, /* 21 = NAK */
508 { FMT_NONE, NULL, NULL, 0 }, /* 22 = EYC */
509 { FMT_NONE, NULL, NULL, 0 }, /* 23 = ETB */
510 { FMT_NONE, NULL, NULL, 0 }, /* 24 = CAN */
511 { FMT_NONE, NULL, NULL, 0 }, /* 25 = EM */
512 { FMT_NONE, NULL, NULL, 0 }, /* 26 = SUB */
513 { FMT_NONE, NULL, NULL, 0 }, /* 27 = ESC */
514 { FMT_NONE, NULL, NULL, 0 }, /* 28 = FS */
515 { FMT_NONE, NULL, NULL, 0 }, /* 29 = GS */
516 { FMT_NONE, NULL, NULL, 0 }, /* 30 = RS */
517 { FMT_NONE, NULL, NULL, 0 }, /* 31 = US */
518 { FMT_NONE, NULL, NULL, 0 }, /* 32 = SPACE */
519 { FMT_NONE, NULL, NULL, 0 }, /* 33 = ! */
520 { FMT_NONE, NULL, NULL, 0 }, /* 34 = " */
521 { FMT_NONE, NULL, NULL, 0 }, /* 35 = # */
522 { FMT_NONE, NULL, NULL, 0 }, /* 36 = $ */
523 { FMT_NONE, NULL, NULL, 0 }, /* 37 = % */
524 { FMT_NONE, NULL, NULL, 0 }, /* 38 = & */
525 { FMT_NONE, NULL, NULL, 0 }, /* 39 = ' */
526 { FMT_NONE, NULL, NULL, 0 }, /* 40 = ( */
527 { FMT_NONE, NULL, NULL, 0 }, /* 41 = ) */
528 { FMT_NONE, NULL, NULL, 0 }, /* 42 = * */
529 { FMT_FUNC, FUNCP(fmt_plus), help_plus, 0 }, /* 43 = + */
530 { FMT_NONE, NULL, NULL, 0 }, /* 44 = , */
531 { FMT_FUNC, FUNCP(fmt_minus), help_minus, 0 }, /* 45 = - */
532 { FMT_NONE, NULL, NULL, 0 }, /* 46 = . */
533 { FMT_NONE, NULL, NULL, 0 }, /* 47 = / */
534 { FMT_NONE, NULL, NULL, 0 }, /* 48 = 0 */
535 { FMT_NONE, NULL, NULL, 0 }, /* 49 = 1 */
536 { FMT_NONE, NULL, NULL, 0 }, /* 50 = 2 */
537 { FMT_NONE, NULL, NULL, 0 }, /* 51 = 3 */
538 { FMT_NONE, NULL, NULL, 0 }, /* 52 = 4 */
539 { FMT_NONE, NULL, NULL, 0 }, /* 53 = 5 */
540 { FMT_NONE, NULL, NULL, 0 }, /* 54 = 6 */
541 { FMT_NONE, NULL, NULL, 0 }, /* 55 = 7 */
542 { FMT_NONE, NULL, NULL, 0 }, /* 56 = 8 */
543 { FMT_NONE, NULL, NULL, 0 }, /* 57 = 9 */
544 { FMT_NONE, NULL, NULL, 0 }, /* 58 = : */
545 { FMT_NONE, NULL, NULL, 0 }, /* 59 = ; */
546 { FMT_NONE, NULL, NULL, 0 }, /* 60 = < */
547 { FMT_NONE, NULL, NULL, 0 }, /* 61 = = */
548 { FMT_NONE, NULL, NULL, 0 }, /* 62 = > */
549 { FMT_NONE, NULL, NULL, 0 }, /* 63 = ? */
550 { FMT_NONE, NULL, NULL, 0 }, /* 64 = @ */
551 { FMT_NONE, NULL, NULL, 0 }, /* 65 = A */
552 { FMT_PRINTF, "%-8x", NULL, 1 }, /* 66 = B */
553 { FMT_FUNC, FUNCP(fmt_escchr), help_escchr, 1 }, /* 67 = C */
554 { FMT_PRINTF, "%-16d", NULL, 4 }, /* 68 = D */
555 { FMT_PRINTF, "%-16llu", NULL, 8 }, /* 69 = E */
556 #ifdef _KMDB
557 { FMT_NONE, NULL, NULL, 0 }, /* 70 = F */
558 #else
559 { FMT_PRINTF, "%g", NULL, sizeof (double) }, /* 70 = F */
560 #endif
561 { FMT_PRINTF, "%-16llo", NULL, 8 }, /* 71 = G */
562 { FMT_FUNC, FUNCP(fmt_swapint), help_swapint, 4 }, /* 72 = H */
563 { FMT_FUNC, FUNCP(fmt_dotinstr), help_dotinstr, 0 }, /* 73 = I */
564 { FMT_FUNC, FUNCP(fmt_hex64), help_hex64, 8 }, /* 74 = J */
565 #ifdef _LP64
566 { FMT_FUNC, FUNCP(fmt_hex64), help_uintptr, 8 }, /* 75 = K (J) */
567 #else
568 { FMT_PRINTF, "%-16x", help_uintptr, 4 }, /* 75 = K (X) */
569 #endif
570 { FMT_MATCH, NULL, help_match32, 4 }, /* 76 = L */
571 { FMT_MATCH, NULL, help_match64, 8 }, /* 77 = M */
572 { FMT_FUNC, FUNCP(fmt_nl), help_nl, SZ_NONE }, /* 78 = N */
573 { FMT_PRINTF, "%-#16o", NULL, 4 }, /* 79 = O */
574 { FMT_PRINTF, "%-16a", NULL, sizeof (uintptr_t) }, /* 80 = P */
575 { FMT_PRINTF, "%-#16q", NULL, 4 }, /* 81 = Q */
576 { FMT_FUNC, FUNCP(fmt_binary), help_binary, 8 }, /* 82 = R */
577 { FMT_FUNC, FUNCP(fmt_escstr), help_escstr, 0 }, /* 83 = S */
578 { FMT_FUNC, FUNCP(fmt_tab), help_tab, SZ_NONE }, /* 84 = T */
579 { FMT_PRINTF, "%-16u", NULL, 4 }, /* 85 = U */
580 { FMT_PRINTF, "%-8u", NULL, 1 }, /* 86 = V */
581 { FMT_PRINTF|FMT_WRITE, "%-16r", NULL, 4 }, /* 87 = W */
582 { FMT_PRINTF, "%-16x", NULL, 4 }, /* 88 = X */
583 { FMT_FUNC, FUNCP(fmt_time32), help_time32, 4 }, /* 89 = Y */
584 { FMT_FUNC|FMT_WRITE, FUNCP(fmt_hex64), help_hex64, 8 }, /* 90 = Z */
585 { FMT_NONE, NULL, NULL, 0 }, /* 91 = [ */
586 { FMT_NONE, NULL, NULL, 0 }, /* 92 = \ */
587 { FMT_NONE, NULL, NULL, 0 }, /* 93 = ] */
588 { FMT_FUNC, FUNCP(fmt_carat), help_carat, 0 }, /* 94 = ^ */
589 { FMT_NONE, NULL, NULL, 0 }, /* 95 = _ */
590 { FMT_NONE, NULL, NULL, 0 }, /* 96 = ` */
591 { FMT_FUNC, FUNCP(fmt_dot), help_dot, SZ_NONE }, /* 97 = a */
592 { FMT_PRINTF, "%-#8o", NULL, 1 }, /* 98 = b */
593 { FMT_PRINTF, "%c", NULL, 1 }, /* 99 = c */
594 { FMT_PRINTF, "%-8hd", NULL, 2 }, /* 100 = d */
595 { FMT_PRINTF, "%-16lld", NULL, 8 }, /* 101 = e */
596 #ifdef _KMDB
597 { FMT_NONE, NULL, NULL, 0 }, /* 102 = f */
598 #else
599 { FMT_FUNC, FUNCP(fmt_float), help_f, sizeof (float) }, /* 102 = f */
600 #endif
601 { FMT_PRINTF, "%-16llq", NULL, 8 }, /* 103 = g */
602 { FMT_FUNC, FUNCP(fmt_swapshort), help_swapshort, 2 }, /* 104 = h */
603 { FMT_FUNC, FUNCP(fmt_instr), help_instr, 0 }, /* 105 = i */
604 { FMT_NONE, NULL, NULL, 0 }, /* 106 = j */
605 { FMT_NONE, NULL, NULL, 0 }, /* 107 = k */
606 { FMT_MATCH, NULL, help_match16, 2 }, /* 108 = l */
607 { FMT_NONE, NULL, NULL, 0 }, /* 109 = m */
608 { FMT_FUNC, FUNCP(fmt_nl), help_nl, SZ_NONE }, /* 110 = n */
609 { FMT_PRINTF, "%-#8ho", NULL, 2 }, /* 111 = o */
610 { FMT_PRINTF, "%-16a", NULL, sizeof (uintptr_t) }, /* 112 = p */
611 { FMT_PRINTF, "%-#8hq", NULL, 2 }, /* 113 = q */
612 { FMT_FUNC, FUNCP(fmt_ws), help_ws, SZ_NONE }, /* 114 = r */
613 { FMT_FUNC, FUNCP(fmt_rawstr), help_rawstr, 0 }, /* 115 = s */
614 { FMT_FUNC, FUNCP(fmt_tab), help_tab, SZ_NONE }, /* 116 = t */
615 { FMT_PRINTF, "%-8hu", NULL, 2 }, /* 117 = u */
616 { FMT_FUNC|FMT_WRITE, FUNCP(fmt_sdbyte), help_sdbyte, 1 }, /* 118 = v */
617 { FMT_PRINTF|FMT_WRITE, "%-8hr", NULL, 2 }, /* 119 = w */
618 { FMT_PRINTF, "%-8hx", NULL, 2 }, /* 120 = x */
619 { FMT_FUNC, FUNCP(fmt_time64), help_time64, 8 }, /* 121 = y */
620 { FMT_NONE, NULL, NULL, 0 }, /* 122 = z */
621 };
622
623 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)624 mdb_fmt_print(mdb_tgt_t *t, mdb_tgt_as_t as,
625 mdb_tgt_addr_t addr, size_t cnt, char fmt)
626 {
627 const mdb_fmt_desc_t *fp = &fmttab[fmt];
628 mdb_fmt_func_f *funcp;
629 uintmax_t rvalue;
630 void *buf;
631
632 union {
633 uint64_t i8;
634 uint32_t i4;
635 uint16_t i2;
636 uint8_t i1;
637 } u;
638
639 if (fmt < 0 || fmt > (sizeof (fmttab) / sizeof (fmttab[0]))) {
640 warn("invalid format character -- '%c'\n", fmt);
641 return (addr);
642 }
643
644 switch (FMT_TYPE(fp->f_type)) {
645 case FMT_FUNC:
646 funcp = (mdb_fmt_func_f *)fp->f_ptr;
647 addr = funcp(t, as, addr, cnt);
648 break;
649
650 case FMT_PRINTF:
651 switch (fp->f_size) {
652 case 1:
653 buf = &u.i1;
654 break;
655 case 2:
656 buf = &u.i2;
657 break;
658 case 4:
659 buf = &u.i4;
660 break;
661 case 8:
662 buf = &u.i8;
663 break;
664 default:
665 fail("format %c is defined using illegal size\n", fmt);
666 }
667
668 while (cnt-- != 0) {
669 if (mdb_tgt_aread(t, as, buf, fp->f_size, addr) !=
670 fp->f_size) {
671 warn("failed to read data from target");
672 return (addr);
673 }
674
675 switch (fp->f_size) {
676 case 1:
677 mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i1);
678 rvalue = u.i1;
679 break;
680 case 2:
681 mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i2);
682 rvalue = u.i2;
683 break;
684 case 4:
685 mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i4);
686 rvalue = u.i4;
687 break;
688 case 8:
689 mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i8);
690 rvalue = u.i8;
691 break;
692 }
693
694 mdb_nv_set_value(mdb.m_rvalue, rvalue);
695 addr += fp->f_size;
696 }
697 break;
698
699 default:
700 warn("invalid format character -- '%c'\n", fmt);
701 }
702
703 return (addr);
704 }
705
706 /*ARGSUSED*/
707 int
cmd_formats(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)708 cmd_formats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
709 {
710 const mdb_fmt_desc_t *fp = &fmttab[0];
711 int i;
712 const char *write;
713
714 if ((flags & DCMD_ADDRSPEC) || argc != 0)
715 return (DCMD_USAGE);
716
717 for (i = 0; i < (sizeof (fmttab) / sizeof (fmttab[0])); i++, fp++) {
718 if (fp->f_type == FMT_NONE)
719 continue;
720
721 write = (fp->f_type & FMT_WRITE) ? "write " : "";
722
723 if (fp->f_type & FMT_FUNC)
724 mdb_printf("%c - %s%s", i, write, fp->f_help);
725 else if (fp->f_type & FMT_MATCH)
726 mdb_printf("%c - match %s", i, fp->f_help);
727 else if (fp->f_help != NULL)
728 mdb_printf("%c - %s%s", i, write, fp->f_help);
729 else
730 mdb_printf("%c - %s%s", i, write,
731 mdb_iob_format2str(fp->f_ptr));
732
733 switch (fp->f_size) {
734 case SZ_NONE:
735 mdb_printf("\n");
736 break;
737 case 0:
738 mdb_printf(" (variable size)\n");
739 break;
740 case 1:
741 mdb_printf(" (1 byte)\n");
742 break;
743 default:
744 mdb_printf(" (%lu bytes)\n", fp->f_size);
745 }
746 }
747
748 return (DCMD_OK);
749 }
750