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 2016 Joyent, Inc. 25 */ 26 27 /* 28 * Format String Decoder 29 * 30 * This file provides the core engine for converting strings of format 31 * characters into formatted output. The various format dcmds invoke the 32 * mdb_fmt_print() function below with a target, address space identifier, 33 * address, count, and format character, and it reads the required data from 34 * the target and prints the formatted output to stdout. Since nearly two 35 * thirds of the format characters can be expressed as simple printf format 36 * strings, we implement the engine using the lookup table below. Each entry 37 * provides either a pointer to a printf format string or a pointer to a 38 * function to perform special processing. For the printf case, the 39 * corresponding data size in bytes is also supplied. The printf processing 40 * code handles 1, 2, 4, and 8-byte reads into an unsigned integer container 41 * of the given size, and then simply calls mdb_iob_printf with the integer 42 * and format string. This handles all printf cases, except when unsigned 43 * promotion of an integer type in the varargs list does not perform the 44 * conversion we require to get the proper result. With the current set of 45 * format characters, this case only occurs twice: we need a 4-byte float 46 * to get promoted to 8-byte double for the 'f' format so it can be 47 * correctly formatted by %f, and we need a 1-byte int8_t to get promoted 48 * with sign extension to a 4-byte int32_t for the 'v' format so it can be 49 * correctly formatted by %d. We provide explicit functions to handle these 50 * cases, as well as to handle special format characters such as 'i', etc. 51 * We also provide a cmd_formats() dcmd function below which prints a table 52 * of the output formats and their sizes. Format characters that provide 53 * custom functions provide their help description string explicitly. All 54 * the printf formats have their help strings generated automatically by 55 * our printf "unparser" mdb_iob_format2str(). 56 */ 57 58 #include <mdb/mdb_types.h> 59 #include <mdb/mdb_target.h> 60 #include <mdb/mdb_io.h> 61 #include <mdb/mdb_err.h> 62 #include <mdb/mdb_string.h> 63 #include <mdb/mdb_modapi.h> 64 #include <mdb/mdb.h> 65 66 #define FUNCP(p) ((void *)(p)) /* Cast to f_ptr type */ 67 #define SZ_NONE ((size_t)-1L) /* Format does not change dot */ 68 69 typedef mdb_tgt_addr_t mdb_fmt_func_f(mdb_tgt_t *, 70 mdb_tgt_as_t, mdb_tgt_addr_t, size_t); 71 72 /* 73 * There are several 'special' characters that are handled outside of 74 * mdb_fmt_print(). These are characters that write (vwWZ) and characters that 75 * match (lLM). We include them here so that ::formats can display an 76 * appropriate message, but they are handled specially by write_arglist() and 77 * match_arglist() in mdb_cmds.c. 78 */ 79 #define FMT_NONE 0x0 /* Format character is not supported */ 80 #define FMT_FUNC 0x1 /* f_ptr is a mdb_fmt_func_f to call */ 81 #define FMT_PRINTF 0x2 /* f_ptr is a const char * format string */ 82 #define FMT_MATCH 0x4 /* Match command (not supported here) */ 83 #define FMT_WRITE 0x8 /* Command writes to address space */ 84 85 #define FMT_TYPE(x) ((x) & 0x7) /* Excludes modifying flags (FMT_WRITE) */ 86 87 typedef struct mdb_fmt_desc { 88 int f_type; /* Type of format (see above) */ 89 void *f_ptr; /* Data pointer (see above) */ 90 const char *f_help; /* Additional help string */ 91 size_t f_size; /* Size of type in bytes, or SZ_NONE */ 92 boolean_t f_float; /* Is this a floating point type */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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), B_TRUE }, /* 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), 600 B_TRUE }, /* 102 = f */ 601 #endif 602 { FMT_PRINTF, "%-16llq", NULL, 8 }, /* 103 = g */ 603 { FMT_FUNC, FUNCP(fmt_swapshort), help_swapshort, 2 }, /* 104 = h */ 604 { FMT_FUNC, FUNCP(fmt_instr), help_instr, 0 }, /* 105 = i */ 605 { FMT_NONE, NULL, NULL, 0 }, /* 106 = j */ 606 { FMT_NONE, NULL, NULL, 0 }, /* 107 = k */ 607 { FMT_MATCH, NULL, help_match16, 2 }, /* 108 = l */ 608 { FMT_NONE, NULL, NULL, 0 }, /* 109 = m */ 609 { FMT_FUNC, FUNCP(fmt_nl), help_nl, SZ_NONE }, /* 110 = n */ 610 { FMT_PRINTF, "%-#8ho", NULL, 2 }, /* 111 = o */ 611 { FMT_PRINTF, "%-16a", NULL, sizeof (uintptr_t) }, /* 112 = p */ 612 { FMT_PRINTF, "%-#8hq", NULL, 2 }, /* 113 = q */ 613 { FMT_FUNC, FUNCP(fmt_ws), help_ws, SZ_NONE }, /* 114 = r */ 614 { FMT_FUNC, FUNCP(fmt_rawstr), help_rawstr, 0 }, /* 115 = s */ 615 { FMT_FUNC, FUNCP(fmt_tab), help_tab, SZ_NONE }, /* 116 = t */ 616 { FMT_PRINTF, "%-8hu", NULL, 2 }, /* 117 = u */ 617 { FMT_FUNC|FMT_WRITE, FUNCP(fmt_sdbyte), help_sdbyte, 1 }, /* 118 = v */ 618 { FMT_PRINTF|FMT_WRITE, "%-8hr", NULL, 2 }, /* 119 = w */ 619 { FMT_PRINTF, "%-8hx", NULL, 2 }, /* 120 = x */ 620 { FMT_FUNC, FUNCP(fmt_time64), help_time64, 8 }, /* 121 = y */ 621 { FMT_NONE, NULL, NULL, 0 }, /* 122 = z */ 622 }; 623 624 mdb_tgt_addr_t 625 mdb_fmt_print(mdb_tgt_t *t, mdb_tgt_as_t as, 626 mdb_tgt_addr_t addr, size_t cnt, char fmt) 627 { 628 const mdb_fmt_desc_t *fp = &fmttab[fmt]; 629 mdb_fmt_func_f *funcp; 630 uintmax_t rvalue; 631 void *buf; 632 633 union { 634 uint64_t i8; 635 uint32_t i4; 636 uint16_t i2; 637 uint8_t i1; 638 double d; 639 } u; 640 641 if (fmt < 0 || fmt > (sizeof (fmttab) / sizeof (fmttab[0]))) { 642 warn("invalid format character -- '%c'\n", fmt); 643 return (addr); 644 } 645 646 switch (FMT_TYPE(fp->f_type)) { 647 case FMT_FUNC: 648 funcp = (mdb_fmt_func_f *)fp->f_ptr; 649 addr = funcp(t, as, addr, cnt); 650 break; 651 652 case FMT_PRINTF: 653 switch (fp->f_size) { 654 case 1: 655 buf = &u.i1; 656 break; 657 case 2: 658 buf = &u.i2; 659 break; 660 case 4: 661 buf = &u.i4; 662 break; 663 case 8: 664 buf = &u.i8; 665 break; 666 default: 667 fail("format %c is defined using illegal size\n", fmt); 668 } 669 670 if (fp->f_float == B_TRUE) { 671 if (fp->f_size != 8) { 672 fail("format %c is using illegal fp size\n", 673 fmt); 674 } 675 676 buf = &u.d; 677 } 678 679 while (cnt-- != 0) { 680 if (mdb_tgt_aread(t, as, buf, fp->f_size, addr) != 681 fp->f_size) { 682 warn("failed to read data from target"); 683 return (addr); 684 } 685 686 switch (fp->f_size) { 687 case 1: 688 mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i1); 689 rvalue = u.i1; 690 break; 691 case 2: 692 mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i2); 693 rvalue = u.i2; 694 break; 695 case 4: 696 mdb_iob_printf(mdb.m_out, fp->f_ptr, u.i4); 697 rvalue = u.i4; 698 break; 699 case 8: 700 if (fp->f_float) { 701 mdb_iob_printf(mdb.m_out, fp->f_ptr, 702 u.d); 703 } else { 704 mdb_iob_printf(mdb.m_out, fp->f_ptr, 705 u.i8); 706 } 707 rvalue = u.i8; 708 break; 709 } 710 711 mdb_nv_set_value(mdb.m_rvalue, rvalue); 712 addr += fp->f_size; 713 } 714 break; 715 716 default: 717 warn("invalid format character -- '%c'\n", fmt); 718 } 719 720 return (addr); 721 } 722 723 /*ARGSUSED*/ 724 int 725 cmd_formats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 726 { 727 const mdb_fmt_desc_t *fp = &fmttab[0]; 728 int i; 729 const char *write; 730 731 if ((flags & DCMD_ADDRSPEC) || argc != 0) 732 return (DCMD_USAGE); 733 734 for (i = 0; i < (sizeof (fmttab) / sizeof (fmttab[0])); i++, fp++) { 735 if (fp->f_type == FMT_NONE) 736 continue; 737 738 write = (fp->f_type & FMT_WRITE) ? "write " : ""; 739 740 if (fp->f_type & FMT_FUNC) 741 mdb_printf("%c - %s%s", i, write, fp->f_help); 742 else if (fp->f_type & FMT_MATCH) 743 mdb_printf("%c - match %s", i, fp->f_help); 744 else if (fp->f_help != NULL) 745 mdb_printf("%c - %s%s", i, write, fp->f_help); 746 else 747 mdb_printf("%c - %s%s", i, write, 748 mdb_iob_format2str(fp->f_ptr)); 749 750 switch (fp->f_size) { 751 case SZ_NONE: 752 mdb_printf("\n"); 753 break; 754 case 0: 755 mdb_printf(" (variable size)\n"); 756 break; 757 case 1: 758 mdb_printf(" (1 byte)\n"); 759 break; 760 default: 761 mdb_printf(" (%lu bytes)\n", fp->f_size); 762 } 763 } 764 765 return (DCMD_OK); 766 } 767