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