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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 } 809 810 mdb_nv_set_value(mdb.m_rvalue, rvalue); 811 addr += fp->f_size; 812 } 813 break; 814 815 default: 816 warn("invalid format character -- '%c'\n", fmt); 817 } 818 819 mdb.m_flags = oflags; 820 821 return (addr); 822 } 823 824 /*ARGSUSED*/ 825 int 826 cmd_formats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 827 { 828 const mdb_fmt_desc_t *fp = &fmttab[0]; 829 int i; 830 const char *write; 831 832 if ((flags & DCMD_ADDRSPEC) || argc != 0) 833 return (DCMD_USAGE); 834 835 for (i = 0; i < (sizeof (fmttab) / sizeof (fmttab[0])); i++, fp++) { 836 if (fp->f_type == FMT_NONE) 837 continue; 838 839 write = (fp->f_type & FMT_WRITE) ? "write " : ""; 840 841 if (fp->f_type & FMT_FUNC) 842 mdb_printf("%c - %s%s", i, write, fp->f_help); 843 else if (fp->f_type & FMT_MATCH) 844 mdb_printf("%c - match %s", i, fp->f_help); 845 else if (fp->f_help != NULL) 846 mdb_printf("%c - %s%s", i, write, fp->f_help); 847 else 848 mdb_printf("%c - %s%s", i, write, 849 mdb_iob_format2str(fp->f_ptr)); 850 851 switch (fp->f_size) { 852 case SZ_NONE: 853 mdb_printf("\n"); 854 break; 855 case 0: 856 mdb_printf(" (variable size)\n"); 857 break; 858 case 1: 859 mdb_printf(" (1 byte)\n"); 860 break; 861 default: 862 mdb_printf(" (%lu bytes)\n", fp->f_size); 863 } 864 } 865 866 return (DCMD_OK); 867 } 868