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 * MDB uses its own enhanced standard i/o mechanism for all input and output. 30 * This file provides the underpinnings of this mechanism, including the 31 * printf-style formatting code, the output pager, and APIs for raw input 32 * and output. This mechanism is used throughout the debugger for everything 33 * from simple sprintf and printf-style formatting, to input to the lexer 34 * and parser, to raw file i/o for reading ELF files. In general, we divide 35 * our i/o implementation into two parts: 36 * 37 * (1) An i/o buffer (mdb_iob_t) provides buffered read or write capabilities, 38 * as well as access to formatting and the ability to invoke a pager. The 39 * buffer is constructed explicitly for use in either reading or writing; it 40 * may not be used for both simultaneously. 41 * 42 * (2) Each i/o buffer is associated with an underlying i/o backend (mdb_io_t). 43 * The backend provides, through an ops-vector, equivalents for the standard 44 * read, write, lseek, ioctl, and close operations. In addition, the backend 45 * can provide an IOP_NAME entry point for returning a name for the backend, 46 * IOP_LINK and IOP_UNLINK entry points that are called when the backend is 47 * connected or disconnected from an mdb_iob_t, and an IOP_SETATTR entry point 48 * for manipulating terminal attributes. 49 * 50 * The i/o objects themselves are reference counted so that more than one i/o 51 * buffer may make use of the same i/o backend. In addition, each buffer 52 * provides the ability to push or pop backends to interpose on input or output 53 * behavior. We make use of this, for example, to implement interactive 54 * session logging. Normally, the stdout iob has a backend that is either 55 * file descriptor 1, or a terminal i/o backend associated with the tty. 56 * However, we can push a log i/o backend on top that multiplexes stdout to 57 * the original back-end and another backend that writes to a log file. The 58 * use of i/o backends is also used for simplifying tasks such as making 59 * lex and yacc read from strings for mdb_eval(), and making our ELF file 60 * processing code read executable "files" from a crash dump via kvm_uread. 61 * 62 * Additionally, the formatting code provides auto-wrap and indent facilities 63 * that are necessary for compatibility with adb macro formatting. In auto- 64 * wrap mode, the formatting code examines each new chunk of output to determine 65 * if it will fit on the current line. If not, instead of having the chunk 66 * divided between the current line of output and the next, the auto-wrap 67 * code will automatically output a newline, auto-indent the next line, 68 * and then continue. Auto-indent is implemented by simply prepending a number 69 * of blanks equal to iob_margin to the start of each line. The margin is 70 * inserted when the iob is created, and following each flush of the buffer. 71 */ 72 73 #include <sys/types.h> 74 #include <sys/termios.h> 75 #include <stdarg.h> 76 #include <arpa/inet.h> 77 #include <sys/socket.h> 78 79 #include <mdb/mdb_types.h> 80 #include <mdb/mdb_argvec.h> 81 #include <mdb/mdb_stdlib.h> 82 #include <mdb/mdb_string.h> 83 #include <mdb/mdb_target.h> 84 #include <mdb/mdb_signal.h> 85 #include <mdb/mdb_debug.h> 86 #include <mdb/mdb_io_impl.h> 87 #include <mdb/mdb_modapi.h> 88 #include <mdb/mdb_demangle.h> 89 #include <mdb/mdb_err.h> 90 #include <mdb/mdb_nv.h> 91 #include <mdb/mdb_frame.h> 92 #include <mdb/mdb_lex.h> 93 #include <mdb/mdb.h> 94 95 /* 96 * Define list of possible integer sizes for conversion routines: 97 */ 98 typedef enum { 99 SZ_SHORT, /* format %h? */ 100 SZ_INT, /* format %? */ 101 SZ_LONG, /* format %l? */ 102 SZ_LONGLONG /* format %ll? */ 103 } intsize_t; 104 105 /* 106 * The iob snprintf family of functions makes use of a special "sprintf 107 * buffer" i/o backend in order to provide the appropriate snprintf semantics. 108 * This structure is maintained as the backend-specific private storage, 109 * and its use is described in more detail below (see spbuf_write()). 110 */ 111 typedef struct { 112 char *spb_buf; /* pointer to underlying buffer */ 113 size_t spb_bufsiz; /* length of underlying buffer */ 114 size_t spb_total; /* total of all bytes passed via IOP_WRITE */ 115 } spbuf_t; 116 117 /* 118 * Define VA_ARG macro for grabbing the next datum to format for the printf 119 * family of functions. We use VA_ARG so that we can support two kinds of 120 * argument lists: the va_list type supplied by <stdarg.h> used for printf and 121 * vprintf, and an array of mdb_arg_t structures, which we expect will be 122 * either type STRING or IMMEDIATE. The vec_arg function takes care of 123 * handling the mdb_arg_t case. 124 */ 125 126 typedef enum { 127 VAT_VARARGS, /* va_list is a va_list */ 128 VAT_ARGVEC /* va_list is a const mdb_arg_t[] in disguise */ 129 } vatype_t; 130 131 typedef struct { 132 vatype_t val_type; 133 union { 134 va_list _val_valist; 135 const mdb_arg_t *_val_argv; 136 } _val_u; 137 } varglist_t; 138 139 #define val_valist _val_u._val_valist 140 #define val_argv _val_u._val_argv 141 142 #define VA_ARG(ap, type) ((ap->val_type == VAT_VARARGS) ? \ 143 va_arg(ap->val_valist, type) : (type)vec_arg(&ap->val_argv)) 144 #define VA_PTRARG(ap) ((ap->val_type == VAT_VARARGS) ? \ 145 (void *)va_arg(ap->val_valist, uintptr_t) : \ 146 (void *)(uintptr_t)vec_arg(&ap->val_argv)) 147 148 /* 149 * Define macro for converting char constant to Ctrl-char equivalent: 150 */ 151 #ifndef CTRL 152 #define CTRL(c) ((c) & 0x01f) 153 #endif 154 155 /* 156 * Define macro for determining if we should automatically wrap to the next 157 * line of output, based on the amount of consumed buffer space and the 158 * specified size of the next thing to be inserted (n). 159 */ 160 #define IOB_WRAPNOW(iob, n) \ 161 (((iob)->iob_flags & MDB_IOB_AUTOWRAP) && ((iob)->iob_nbytes != 0) && \ 162 ((n) + (iob)->iob_nbytes > (iob)->iob_cols)) 163 164 /* 165 * Define prompt string and string to erase prompt string for iob_pager 166 * function, which is invoked if the pager is enabled on an i/o buffer 167 * and we're about to print a line which would be the last on the screen. 168 */ 169 170 static const char io_prompt[] = ">> More [<space>, <cr>, q, n, c, a] ? "; 171 static const char io_perase[] = " "; 172 173 static const char io_pbcksp[] = 174 /*CSTYLED*/ 175 "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; 176 177 static const size_t io_promptlen = sizeof (io_prompt) - 1; 178 static const size_t io_peraselen = sizeof (io_perase) - 1; 179 static const size_t io_pbcksplen = sizeof (io_pbcksp) - 1; 180 181 static ssize_t 182 iob_write(mdb_iob_t *iob, mdb_io_t *io, const void *buf, size_t n) 183 { 184 ssize_t resid = n; 185 ssize_t len; 186 187 while (resid != 0) { 188 if ((len = IOP_WRITE(io, buf, resid)) <= 0) 189 break; 190 191 buf = (char *)buf + len; 192 resid -= len; 193 } 194 195 /* 196 * Note that if we had a partial write before an error, we still want 197 * to return the fact something was written. The caller will get an 198 * error next time it tries to write anything. 199 */ 200 if (resid == n && n != 0) { 201 iob->iob_flags |= MDB_IOB_ERR; 202 return (-1); 203 } 204 205 return (n - resid); 206 } 207 208 static ssize_t 209 iob_read(mdb_iob_t *iob, mdb_io_t *io) 210 { 211 ssize_t len; 212 213 ASSERT(iob->iob_nbytes == 0); 214 len = IOP_READ(io, iob->iob_buf, iob->iob_bufsiz); 215 iob->iob_bufp = &iob->iob_buf[0]; 216 217 switch (len) { 218 case -1: 219 iob->iob_flags |= MDB_IOB_ERR; 220 break; 221 case 0: 222 iob->iob_flags |= MDB_IOB_EOF; 223 break; 224 default: 225 iob->iob_nbytes = len; 226 } 227 228 return (len); 229 } 230 231 /*ARGSUSED*/ 232 static void 233 iob_winch(int sig, siginfo_t *sip, ucontext_t *ucp, void *data) 234 { 235 siglongjmp(*((sigjmp_buf *)data), sig); 236 } 237 238 static int 239 iob_pager(mdb_iob_t *iob) 240 { 241 int status = 0; 242 sigjmp_buf env; 243 uchar_t c; 244 245 mdb_signal_f *termio_winch; 246 void *termio_data; 247 size_t old_rows; 248 249 if (iob->iob_pgp == NULL || (iob->iob_flags & MDB_IOB_PGCONT)) 250 return (0); 251 252 termio_winch = mdb_signal_gethandler(SIGWINCH, &termio_data); 253 (void) mdb_signal_sethandler(SIGWINCH, iob_winch, &env); 254 255 if (sigsetjmp(env, 1) != 0) { 256 /* 257 * Reset the cursor back to column zero before printing a new 258 * prompt, since its position is unreliable after a SIGWINCH. 259 */ 260 (void) iob_write(iob, iob->iob_pgp, "\r", sizeof (char)); 261 old_rows = iob->iob_rows; 262 263 /* 264 * If an existing SIGWINCH handler was present, call it. We 265 * expect that this will be termio: the handler will read the 266 * new window size, and then resize this iob appropriately. 267 */ 268 if (termio_winch != (mdb_signal_f *)NULL) 269 termio_winch(SIGWINCH, NULL, NULL, termio_data); 270 271 /* 272 * If the window has increased in size, we treat this like a 273 * request to fill out the new remainder of the page. 274 */ 275 if (iob->iob_rows > old_rows) { 276 iob->iob_flags &= ~MDB_IOB_PGSINGLE; 277 iob->iob_nlines = old_rows; 278 status = 0; 279 goto winch; 280 } 281 } 282 283 (void) iob_write(iob, iob->iob_pgp, io_prompt, io_promptlen); 284 285 for (;;) { 286 if (IOP_READ(iob->iob_pgp, &c, sizeof (c)) != sizeof (c)) { 287 status = MDB_ERR_PAGER; 288 break; 289 } 290 291 switch (c) { 292 case 'N': 293 case 'n': 294 case '\n': 295 case '\r': 296 iob->iob_flags |= MDB_IOB_PGSINGLE; 297 goto done; 298 299 case CTRL('c'): 300 case CTRL('\\'): 301 case 'Q': 302 case 'q': 303 mdb_iob_discard(iob); 304 status = MDB_ERR_PAGER; 305 goto done; 306 307 case 'A': 308 case 'a': 309 mdb_iob_discard(iob); 310 status = MDB_ERR_ABORT; 311 goto done; 312 313 case 'C': 314 case 'c': 315 iob->iob_flags |= MDB_IOB_PGCONT; 316 /*FALLTHRU*/ 317 318 case ' ': 319 iob->iob_flags &= ~MDB_IOB_PGSINGLE; 320 goto done; 321 } 322 } 323 324 done: 325 (void) iob_write(iob, iob->iob_pgp, io_pbcksp, io_pbcksplen); 326 winch: 327 (void) iob_write(iob, iob->iob_pgp, io_perase, io_peraselen); 328 (void) iob_write(iob, iob->iob_pgp, io_pbcksp, io_pbcksplen); 329 (void) mdb_signal_sethandler(SIGWINCH, termio_winch, termio_data); 330 331 if ((iob->iob_flags & MDB_IOB_ERR) && status == 0) 332 status = MDB_ERR_OUTPUT; 333 334 return (status); 335 } 336 337 static void 338 iob_indent(mdb_iob_t *iob) 339 { 340 if (iob->iob_nbytes == 0 && iob->iob_margin != 0 && 341 (iob->iob_flags & MDB_IOB_INDENT)) { 342 size_t i; 343 344 ASSERT(iob->iob_margin < iob->iob_cols); 345 ASSERT(iob->iob_bufp == iob->iob_buf); 346 347 for (i = 0; i < iob->iob_margin; i++) 348 *iob->iob_bufp++ = ' '; 349 350 iob->iob_nbytes = iob->iob_margin; 351 } 352 } 353 354 static void 355 iob_unindent(mdb_iob_t *iob) 356 { 357 if (iob->iob_nbytes != 0 && iob->iob_nbytes == iob->iob_margin) { 358 const char *p = iob->iob_buf; 359 360 while (p < &iob->iob_buf[iob->iob_margin]) { 361 if (*p++ != ' ') 362 return; 363 } 364 365 iob->iob_bufp = &iob->iob_buf[0]; 366 iob->iob_nbytes = 0; 367 } 368 } 369 370 mdb_iob_t * 371 mdb_iob_create(mdb_io_t *io, uint_t flags) 372 { 373 mdb_iob_t *iob = mdb_alloc(sizeof (mdb_iob_t), UM_SLEEP); 374 375 iob->iob_buf = mdb_alloc(BUFSIZ, UM_SLEEP); 376 iob->iob_bufsiz = BUFSIZ; 377 iob->iob_bufp = &iob->iob_buf[0]; 378 iob->iob_nbytes = 0; 379 iob->iob_nlines = 0; 380 iob->iob_lineno = 1; 381 iob->iob_rows = MDB_IOB_DEFROWS; 382 iob->iob_cols = MDB_IOB_DEFCOLS; 383 iob->iob_tabstop = MDB_IOB_DEFTAB; 384 iob->iob_margin = MDB_IOB_DEFMARGIN; 385 iob->iob_flags = flags & ~(MDB_IOB_EOF|MDB_IOB_ERR) | MDB_IOB_AUTOWRAP; 386 iob->iob_iop = mdb_io_hold(io); 387 iob->iob_pgp = NULL; 388 iob->iob_next = NULL; 389 390 IOP_LINK(io, iob); 391 iob_indent(iob); 392 return (iob); 393 } 394 395 void 396 mdb_iob_pipe(mdb_iob_t **iobs, mdb_iobsvc_f *rdsvc, mdb_iobsvc_f *wrsvc) 397 { 398 mdb_io_t *pio = mdb_pipeio_create(rdsvc, wrsvc); 399 int i; 400 401 iobs[0] = mdb_iob_create(pio, MDB_IOB_RDONLY); 402 iobs[1] = mdb_iob_create(pio, MDB_IOB_WRONLY); 403 404 for (i = 0; i < 2; i++) { 405 iobs[i]->iob_flags &= ~MDB_IOB_AUTOWRAP; 406 iobs[i]->iob_cols = iobs[i]->iob_bufsiz; 407 } 408 } 409 410 void 411 mdb_iob_destroy(mdb_iob_t *iob) 412 { 413 /* 414 * Don't flush a pipe, since it may cause a context swith when the 415 * other side has already been destroyed. 416 */ 417 if (!mdb_iob_isapipe(iob)) 418 mdb_iob_flush(iob); 419 420 if (iob->iob_pgp != NULL) 421 mdb_io_rele(iob->iob_pgp); 422 423 while (iob->iob_iop != NULL) { 424 IOP_UNLINK(iob->iob_iop, iob); 425 (void) mdb_iob_pop_io(iob); 426 } 427 428 mdb_free(iob->iob_buf, iob->iob_bufsiz); 429 mdb_free(iob, sizeof (mdb_iob_t)); 430 } 431 432 void 433 mdb_iob_discard(mdb_iob_t *iob) 434 { 435 iob->iob_bufp = &iob->iob_buf[0]; 436 iob->iob_nbytes = 0; 437 } 438 439 void 440 mdb_iob_flush(mdb_iob_t *iob) 441 { 442 int pgerr = 0; 443 444 if (iob->iob_nbytes == 0) 445 return; /* Nothing to do if buffer is empty */ 446 447 if (iob->iob_flags & MDB_IOB_WRONLY) { 448 if (iob->iob_flags & MDB_IOB_PGSINGLE) { 449 iob->iob_flags &= ~MDB_IOB_PGSINGLE; 450 iob->iob_nlines = 0; 451 pgerr = iob_pager(iob); 452 453 } else if (iob->iob_nlines >= iob->iob_rows - 1) { 454 iob->iob_nlines = 0; 455 if (iob->iob_flags & MDB_IOB_PGENABLE) 456 pgerr = iob_pager(iob); 457 } 458 459 if (pgerr == 0) { 460 /* 461 * We only jump out of the dcmd on error if the iob is 462 * m_out. Presumably, if a dcmd has opened a special 463 * file and is writing to it, it will handle errors 464 * properly. 465 */ 466 if (iob_write(iob, iob->iob_iop, iob->iob_buf, 467 iob->iob_nbytes) < 0 && iob == mdb.m_out) 468 pgerr = MDB_ERR_OUTPUT; 469 iob->iob_nlines++; 470 } 471 } 472 473 iob->iob_bufp = &iob->iob_buf[0]; 474 iob->iob_nbytes = 0; 475 iob_indent(iob); 476 477 if (pgerr) 478 longjmp(mdb.m_frame->f_pcb, pgerr); 479 } 480 481 void 482 mdb_iob_nlflush(mdb_iob_t *iob) 483 { 484 iob_unindent(iob); 485 486 if (iob->iob_nbytes != 0) 487 mdb_iob_nl(iob); 488 else 489 iob_indent(iob); 490 } 491 492 void 493 mdb_iob_push_io(mdb_iob_t *iob, mdb_io_t *io) 494 { 495 ASSERT(io->io_next == NULL); 496 497 io->io_next = iob->iob_iop; 498 iob->iob_iop = mdb_io_hold(io); 499 } 500 501 mdb_io_t * 502 mdb_iob_pop_io(mdb_iob_t *iob) 503 { 504 mdb_io_t *io = iob->iob_iop; 505 506 if (io != NULL) { 507 iob->iob_iop = io->io_next; 508 io->io_next = NULL; 509 mdb_io_rele(io); 510 } 511 512 return (io); 513 } 514 515 void 516 mdb_iob_resize(mdb_iob_t *iob, size_t rows, size_t cols) 517 { 518 if (cols > iob->iob_bufsiz) 519 iob->iob_cols = iob->iob_bufsiz; 520 else 521 iob->iob_cols = cols != 0 ? cols : MDB_IOB_DEFCOLS; 522 523 iob->iob_rows = rows != 0 ? rows : MDB_IOB_DEFROWS; 524 } 525 526 void 527 mdb_iob_setpager(mdb_iob_t *iob, mdb_io_t *pgio) 528 { 529 struct winsize winsz; 530 531 if (iob->iob_pgp != NULL) { 532 IOP_UNLINK(iob->iob_pgp, iob); 533 mdb_io_rele(iob->iob_pgp); 534 } 535 536 iob->iob_flags |= MDB_IOB_PGENABLE; 537 iob->iob_flags &= ~(MDB_IOB_PGSINGLE | MDB_IOB_PGCONT); 538 iob->iob_pgp = mdb_io_hold(pgio); 539 540 IOP_LINK(iob->iob_pgp, iob); 541 542 if (IOP_CTL(pgio, TIOCGWINSZ, &winsz) == 0) 543 mdb_iob_resize(iob, (size_t)winsz.ws_row, (size_t)winsz.ws_col); 544 } 545 546 void 547 mdb_iob_tabstop(mdb_iob_t *iob, size_t tabstop) 548 { 549 iob->iob_tabstop = MIN(tabstop, iob->iob_cols - 1); 550 } 551 552 void 553 mdb_iob_margin(mdb_iob_t *iob, size_t margin) 554 { 555 iob_unindent(iob); 556 iob->iob_margin = MIN(margin, iob->iob_cols - 1); 557 iob_indent(iob); 558 } 559 560 void 561 mdb_iob_setbuf(mdb_iob_t *iob, void *buf, size_t bufsiz) 562 { 563 ASSERT(buf != NULL && bufsiz != 0); 564 565 mdb_free(iob->iob_buf, iob->iob_bufsiz); 566 iob->iob_buf = buf; 567 iob->iob_bufsiz = bufsiz; 568 569 if (iob->iob_flags & MDB_IOB_WRONLY) 570 iob->iob_cols = MIN(iob->iob_cols, iob->iob_bufsiz); 571 } 572 573 void 574 mdb_iob_clearlines(mdb_iob_t *iob) 575 { 576 iob->iob_flags &= ~(MDB_IOB_PGSINGLE | MDB_IOB_PGCONT); 577 iob->iob_nlines = 0; 578 } 579 580 void 581 mdb_iob_setflags(mdb_iob_t *iob, uint_t flags) 582 { 583 iob->iob_flags |= flags; 584 if (flags & MDB_IOB_INDENT) 585 iob_indent(iob); 586 } 587 588 void 589 mdb_iob_clrflags(mdb_iob_t *iob, uint_t flags) 590 { 591 iob->iob_flags &= ~flags; 592 if (flags & MDB_IOB_INDENT) 593 iob_unindent(iob); 594 } 595 596 uint_t 597 mdb_iob_getflags(mdb_iob_t *iob) 598 { 599 return (iob->iob_flags); 600 } 601 602 static uintmax_t 603 vec_arg(const mdb_arg_t **app) 604 { 605 uintmax_t value; 606 607 if ((*app)->a_type == MDB_TYPE_STRING) 608 value = (uintmax_t)(uintptr_t)(*app)->a_un.a_str; 609 else 610 value = (*app)->a_un.a_val; 611 612 (*app)++; 613 return (value); 614 } 615 616 static const char * 617 iob_size2str(intsize_t size) 618 { 619 switch (size) { 620 case SZ_SHORT: 621 return ("short"); 622 case SZ_INT: 623 return ("int"); 624 case SZ_LONG: 625 return ("long"); 626 case SZ_LONGLONG: 627 return ("long long"); 628 } 629 return (""); 630 } 631 632 /* 633 * In order to simplify maintenance of the ::formats display, we provide an 634 * unparser for mdb_printf format strings that converts a simple format 635 * string with one specifier into a descriptive representation, e.g. 636 * mdb_iob_format2str("%llx") returns "hexadecimal long long". 637 */ 638 const char * 639 mdb_iob_format2str(const char *format) 640 { 641 intsize_t size = SZ_INT; 642 const char *p; 643 644 static char buf[64]; 645 646 buf[0] = '\0'; 647 648 if ((p = strchr(format, '%')) == NULL) 649 goto done; 650 651 fmt_switch: 652 switch (*++p) { 653 case '0': case '1': case '2': case '3': case '4': 654 case '5': case '6': case '7': case '8': case '9': 655 while (*p >= '0' && *p <= '9') 656 p++; 657 p--; 658 goto fmt_switch; 659 660 case 'a': 661 case 'A': 662 return ("symbol"); 663 664 case 'b': 665 (void) strcpy(buf, "unsigned "); 666 (void) strcat(buf, iob_size2str(size)); 667 (void) strcat(buf, " bitfield"); 668 break; 669 670 case 'c': 671 return ("character"); 672 673 case 'd': 674 case 'i': 675 (void) strcpy(buf, "decimal signed "); 676 (void) strcat(buf, iob_size2str(size)); 677 break; 678 679 case 'e': 680 case 'E': 681 case 'g': 682 case 'G': 683 return ("double"); 684 685 case 'h': 686 size = SZ_SHORT; 687 goto fmt_switch; 688 689 case 'I': 690 return ("IPv4 address"); 691 692 case 'l': 693 if (size >= SZ_LONG) 694 size = SZ_LONGLONG; 695 else 696 size = SZ_LONG; 697 goto fmt_switch; 698 699 case 'm': 700 return ("margin"); 701 702 case 'N': 703 return ("IPv6 address"); 704 705 case 'o': 706 (void) strcpy(buf, "octal unsigned "); 707 (void) strcat(buf, iob_size2str(size)); 708 break; 709 710 case 'p': 711 return ("pointer"); 712 713 case 'q': 714 (void) strcpy(buf, "octal signed "); 715 (void) strcat(buf, iob_size2str(size)); 716 break; 717 718 case 'r': 719 (void) strcpy(buf, "default radix unsigned "); 720 (void) strcat(buf, iob_size2str(size)); 721 break; 722 723 case 'R': 724 (void) strcpy(buf, "default radix signed "); 725 (void) strcat(buf, iob_size2str(size)); 726 break; 727 728 case 's': 729 return ("string"); 730 731 case 't': 732 case 'T': 733 return ("tab"); 734 735 case 'u': 736 (void) strcpy(buf, "decimal unsigned "); 737 (void) strcat(buf, iob_size2str(size)); 738 break; 739 740 case 'x': 741 case 'X': 742 (void) strcat(buf, "hexadecimal "); 743 (void) strcat(buf, iob_size2str(size)); 744 break; 745 746 case 'Y': 747 return ("time_t"); 748 749 case '<': 750 return ("terminal attribute"); 751 752 case '?': 753 case '#': 754 case '+': 755 case '-': 756 goto fmt_switch; 757 } 758 759 done: 760 if (buf[0] == '\0') 761 (void) strcpy(buf, "text"); 762 763 return ((const char *)buf); 764 } 765 766 static const char * 767 iob_int2str(varglist_t *ap, intsize_t size, int base, uint_t flags, int *zero, 768 u_longlong_t *value) 769 { 770 uintmax_t i; 771 772 switch (size) { 773 case SZ_LONGLONG: 774 if (flags & NTOS_UNSIGNED) 775 i = (u_longlong_t)VA_ARG(ap, u_longlong_t); 776 else 777 i = (longlong_t)VA_ARG(ap, longlong_t); 778 break; 779 780 case SZ_LONG: 781 if (flags & NTOS_UNSIGNED) 782 i = (ulong_t)VA_ARG(ap, ulong_t); 783 else 784 i = (long)VA_ARG(ap, long); 785 break; 786 787 case SZ_SHORT: 788 if (flags & NTOS_UNSIGNED) 789 i = (ushort_t)VA_ARG(ap, uint_t); 790 else 791 i = (short)VA_ARG(ap, int); 792 break; 793 794 default: 795 if (flags & NTOS_UNSIGNED) 796 i = (uint_t)VA_ARG(ap, uint_t); 797 else 798 i = (int)VA_ARG(ap, int); 799 } 800 801 *zero = i == 0; /* Return flag indicating if result was zero */ 802 *value = i; /* Return value retrieved from va_list */ 803 804 return (numtostr(i, base, flags)); 805 } 806 807 static const char * 808 iob_time2str(time_t *tmp) 809 { 810 /* 811 * ctime(3c) returns a string of the form 812 * "Fri Sep 13 00:00:00 1986\n\0". We turn this into the canonical 813 * adb /y format "1986 Sep 13 00:00:00" below. 814 */ 815 const char *src = ctime(tmp); 816 static char buf[32]; 817 char *dst = buf; 818 int i; 819 820 if (src == NULL) 821 return (numtostr((uintmax_t)*tmp, mdb.m_radix, 0)); 822 823 for (i = 20; i < 24; i++) 824 *dst++ = src[i]; /* Copy the 4-digit year */ 825 826 for (i = 3; i < 19; i++) 827 *dst++ = src[i]; /* Copy month, day, and h:m:s */ 828 829 *dst = '\0'; 830 return (buf); 831 } 832 833 static const char * 834 iob_addr2str(uintptr_t addr) 835 { 836 static char buf[MDB_TGT_SYM_NAMLEN]; 837 char *name = buf; 838 longlong_t offset; 839 GElf_Sym sym; 840 841 if (mdb_tgt_lookup_by_addr(mdb.m_target, addr, 842 MDB_TGT_SYM_FUZZY, buf, sizeof (buf), &sym, NULL) == -1) 843 return (NULL); 844 845 if (mdb.m_demangler != NULL && (mdb.m_flags & MDB_FL_DEMANGLE)) 846 name = (char *)mdb_dem_convert(mdb.m_demangler, buf); 847 848 /* 849 * Here we provide a little cooperation between the %a formatting code 850 * and the proc target: if the initial address passed to %a is in fact 851 * a PLT address, the proc target's lookup_by_addr code will convert 852 * this to the PLT destination (a different address). We do not want 853 * to append a "+/-offset" suffix based on comparison with the query 854 * symbol in this case because the proc target has really done a hidden 855 * query for us with a different address. We detect this case by 856 * comparing the initial characters of buf to the special PLT= string. 857 */ 858 if (sym.st_value != addr && strncmp(name, "PLT=", 4) != 0) { 859 if (sym.st_value > addr) 860 offset = -(longlong_t)(sym.st_value - addr); 861 else 862 offset = (longlong_t)(addr - sym.st_value); 863 864 (void) strcat(name, numtostr(offset, mdb.m_radix, 865 NTOS_SIGNPOS | NTOS_SHOWBASE)); 866 } 867 868 return (name); 869 } 870 871 static int 872 iob_setattr(mdb_iob_t *iob, const char *s, size_t nbytes) 873 { 874 uint_t attr; 875 int req; 876 877 if (iob->iob_pgp == NULL) 878 return (set_errno(ENOTTY)); 879 880 if (nbytes != 0 && *s == '/') { 881 req = ATT_OFF; 882 nbytes--; 883 s++; 884 } else 885 req = ATT_ON; 886 887 if (nbytes != 1) 888 return (set_errno(EINVAL)); 889 890 switch (*s) { 891 case 's': 892 attr = ATT_STANDOUT; 893 break; 894 case 'u': 895 attr = ATT_UNDERLINE; 896 break; 897 case 'r': 898 attr = ATT_REVERSE; 899 break; 900 case 'b': 901 attr = ATT_BOLD; 902 break; 903 case 'd': 904 attr = ATT_DIM; 905 break; 906 case 'a': 907 attr = ATT_ALTCHARSET; 908 break; 909 default: 910 return (set_errno(EINVAL)); 911 } 912 913 /* 914 * We need to flush the current buffer contents before calling 915 * IOP_SETATTR because IOP_SETATTR may need to synchronously output 916 * terminal escape sequences directly to the underlying device. 917 */ 918 (void) iob_write(iob, iob->iob_iop, iob->iob_buf, iob->iob_nbytes); 919 iob->iob_bufp = &iob->iob_buf[0]; 920 iob->iob_nbytes = 0; 921 922 return (IOP_SETATTR(iob->iob_pgp, req, attr)); 923 } 924 925 static void 926 iob_bits2str(mdb_iob_t *iob, u_longlong_t value, const mdb_bitmask_t *bmp, 927 mdb_bool_t altflag) 928 { 929 mdb_bool_t delim = FALSE; 930 const char *str; 931 size_t width; 932 933 if (bmp == NULL) 934 goto out; 935 936 for (; bmp->bm_name != NULL; bmp++) { 937 if ((value & bmp->bm_mask) == bmp->bm_bits) { 938 width = strlen(bmp->bm_name) + delim; 939 940 if (IOB_WRAPNOW(iob, width)) 941 mdb_iob_nl(iob); 942 943 if (delim) 944 mdb_iob_putc(iob, ','); 945 else 946 delim = TRUE; 947 948 mdb_iob_puts(iob, bmp->bm_name); 949 value &= ~bmp->bm_bits; 950 } 951 } 952 953 out: 954 if (altflag == TRUE && (delim == FALSE || value != 0)) { 955 str = numtostr(value, 16, NTOS_UNSIGNED | NTOS_SHOWBASE); 956 width = strlen(str) + delim; 957 958 if (IOB_WRAPNOW(iob, width)) 959 mdb_iob_nl(iob); 960 if (delim) 961 mdb_iob_putc(iob, ','); 962 mdb_iob_puts(iob, str); 963 } 964 } 965 966 static const char * 967 iob_inaddr2str(uint32_t addr) 968 { 969 static char buf[INET_ADDRSTRLEN]; 970 971 (void) mdb_inet_ntop(AF_INET, &addr, buf, sizeof (buf)); 972 973 return (buf); 974 } 975 976 static const char * 977 iob_ipv6addr2str(void *addr) 978 { 979 static char buf[INET6_ADDRSTRLEN]; 980 981 (void) mdb_inet_ntop(AF_INET6, addr, buf, sizeof (buf)); 982 983 return (buf); 984 } 985 986 static const char * 987 iob_getvar(const char *s, size_t len) 988 { 989 mdb_var_t *val; 990 char *var; 991 992 if (len == 0) { 993 (void) set_errno(EINVAL); 994 return (NULL); 995 } 996 997 var = strndup(s, len); 998 val = mdb_nv_lookup(&mdb.m_nv, var); 999 strfree(var); 1000 1001 if (val == NULL) { 1002 (void) set_errno(EINVAL); 1003 return (NULL); 1004 } 1005 1006 return (numtostr(mdb_nv_get_value(val), 10, 0)); 1007 } 1008 1009 /* 1010 * The iob_doprnt function forms the main engine of the debugger's output 1011 * formatting capabilities. Note that this is NOT exactly compatible with 1012 * the printf(3S) family, nor is it intended to be so. We support some 1013 * extensions and format characters not supported by printf(3S), and we 1014 * explicitly do NOT provide support for %C, %S, %ws (wide-character strings), 1015 * do NOT provide for the complete functionality of %f, %e, %E, %g, %G 1016 * (alternate double formats), and do NOT support %.x (precision specification). 1017 * Note that iob_doprnt consumes varargs off the original va_list. 1018 */ 1019 static void 1020 iob_doprnt(mdb_iob_t *iob, const char *format, varglist_t *ap) 1021 { 1022 char c[2] = { 0, 0 }; /* Buffer for single character output */ 1023 const char *p; /* Current position in format string */ 1024 size_t len; /* Length of format string to copy verbatim */ 1025 size_t altlen; /* Length of alternate print format prefix */ 1026 const char *altstr; /* Alternate print format prefix */ 1027 const char *symstr; /* Symbol + offset string */ 1028 1029 u_longlong_t val; /* Current integer value */ 1030 intsize_t size; /* Current integer value size */ 1031 uint_t flags; /* Current flags to pass to iob_int2str */ 1032 size_t width; /* Current field width */ 1033 int zero; /* If != 0, then integer value == 0 */ 1034 1035 mdb_bool_t f_alt; /* Use alternate print format (%#) */ 1036 mdb_bool_t f_altsuff; /* Alternate print format is a suffix */ 1037 mdb_bool_t f_zfill; /* Zero-fill field (%0) */ 1038 mdb_bool_t f_left; /* Left-adjust field (%-) */ 1039 mdb_bool_t f_digits; /* Explicit digits used to set field width */ 1040 1041 union { 1042 const char *str; 1043 uint32_t ui32; 1044 void *ptr; 1045 time_t tm; 1046 char c; 1047 double d; 1048 long double ld; 1049 } u; 1050 1051 ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 1052 1053 while ((p = strchr(format, '%')) != NULL) { 1054 /* 1055 * Output the format string verbatim up to the next '%' char 1056 */ 1057 if (p != format) { 1058 len = p - format; 1059 if (IOB_WRAPNOW(iob, len) && *format != '\n') 1060 mdb_iob_nl(iob); 1061 mdb_iob_nputs(iob, format, len); 1062 } 1063 1064 /* 1065 * Now we need to parse the sequence of format characters 1066 * following the % marker and do the appropriate thing. 1067 */ 1068 size = SZ_INT; /* Use normal-sized int by default */ 1069 flags = 0; /* Clear numtostr() format flags */ 1070 width = 0; /* No field width limit by default */ 1071 altlen = 0; /* No alternate format string yet */ 1072 altstr = NULL; /* No alternate format string yet */ 1073 1074 f_alt = FALSE; /* Alternate format off by default */ 1075 f_altsuff = FALSE; /* Alternate format is a prefix */ 1076 f_zfill = FALSE; /* Zero-fill off by default */ 1077 f_left = FALSE; /* Left-adjust off by default */ 1078 f_digits = FALSE; /* No digits for width specified yet */ 1079 1080 fmt_switch: 1081 switch (*++p) { 1082 case '0': case '1': case '2': case '3': case '4': 1083 case '5': case '6': case '7': case '8': case '9': 1084 if (f_digits == FALSE && *p == '0') { 1085 f_zfill = TRUE; 1086 goto fmt_switch; 1087 } 1088 1089 if (f_digits == FALSE) 1090 width = 0; /* clear any other width specifier */ 1091 1092 for (u.c = *p; u.c >= '0' && u.c <= '9'; u.c = *++p) 1093 width = width * 10 + u.c - '0'; 1094 1095 p--; 1096 f_digits = TRUE; 1097 goto fmt_switch; 1098 1099 case 'a': 1100 if (size < SZ_LONG) 1101 size = SZ_LONG; /* Bump to size of uintptr_t */ 1102 1103 u.str = iob_int2str(ap, size, 16, 1104 NTOS_UNSIGNED | NTOS_SHOWBASE, &zero, &val); 1105 1106 if ((symstr = iob_addr2str(val)) != NULL) 1107 u.str = symstr; 1108 1109 if (f_alt == TRUE) { 1110 f_altsuff = TRUE; 1111 altstr = ":"; 1112 altlen = 1; 1113 } 1114 break; 1115 1116 case 'A': 1117 if (size < SZ_LONG) 1118 size = SZ_LONG; /* Bump to size of uintptr_t */ 1119 1120 (void) iob_int2str(ap, size, 16, 1121 NTOS_UNSIGNED, &zero, &val); 1122 1123 u.str = iob_addr2str(val); 1124 1125 if (f_alt == TRUE && u.str == NULL) 1126 u.str = "?"; 1127 break; 1128 1129 case 'b': 1130 u.str = iob_int2str(ap, size, 16, 1131 NTOS_UNSIGNED | NTOS_SHOWBASE, &zero, &val); 1132 1133 iob_bits2str(iob, val, VA_PTRARG(ap), f_alt); 1134 1135 format = ++p; 1136 continue; 1137 1138 case 'c': 1139 c[0] = (char)VA_ARG(ap, int); 1140 u.str = c; 1141 break; 1142 1143 case 'd': 1144 case 'i': 1145 if (f_alt) 1146 flags |= NTOS_SHOWBASE; 1147 u.str = iob_int2str(ap, size, 10, flags, &zero, &val); 1148 break; 1149 1150 /* No floating point in kmdb */ 1151 #ifndef _KMDB 1152 case 'e': 1153 case 'E': 1154 u.d = VA_ARG(ap, double); 1155 u.str = doubletos(u.d, 7, *p); 1156 break; 1157 1158 case 'g': 1159 case 'G': 1160 if (size >= SZ_LONG) { 1161 u.ld = VA_ARG(ap, long double); 1162 u.str = longdoubletos(&u.ld, 16, 1163 (*p == 'g') ? 'e' : 'E'); 1164 } else { 1165 u.d = VA_ARG(ap, double); 1166 u.str = doubletos(u.d, 16, 1167 (*p == 'g') ? 'e' : 'E'); 1168 } 1169 break; 1170 #endif 1171 1172 case 'h': 1173 size = SZ_SHORT; 1174 goto fmt_switch; 1175 1176 case 'I': 1177 u.ui32 = VA_ARG(ap, uint32_t); 1178 u.str = iob_inaddr2str(u.ui32); 1179 break; 1180 1181 case 'l': 1182 if (size >= SZ_LONG) 1183 size = SZ_LONGLONG; 1184 else 1185 size = SZ_LONG; 1186 goto fmt_switch; 1187 1188 case 'm': 1189 if (iob->iob_nbytes == 0) { 1190 mdb_iob_ws(iob, (width != 0) ? width : 1191 iob->iob_margin); 1192 } 1193 format = ++p; 1194 continue; 1195 1196 case 'N': 1197 u.ptr = VA_PTRARG(ap); 1198 u.str = iob_ipv6addr2str(u.ptr); 1199 break; 1200 1201 case 'o': 1202 u.str = iob_int2str(ap, size, 8, NTOS_UNSIGNED, 1203 &zero, &val); 1204 1205 if (f_alt && !zero) { 1206 altstr = "0"; 1207 altlen = 1; 1208 } 1209 break; 1210 1211 case 'p': 1212 u.ptr = VA_PTRARG(ap); 1213 u.str = numtostr((uintptr_t)u.ptr, 16, NTOS_UNSIGNED); 1214 break; 1215 1216 case 'q': 1217 u.str = iob_int2str(ap, size, 8, flags, &zero, &val); 1218 1219 if (f_alt && !zero) { 1220 altstr = "0"; 1221 altlen = 1; 1222 } 1223 break; 1224 1225 case 'r': 1226 if (f_alt) 1227 flags |= NTOS_SHOWBASE; 1228 u.str = iob_int2str(ap, size, mdb.m_radix, 1229 NTOS_UNSIGNED | flags, &zero, &val); 1230 break; 1231 1232 case 'R': 1233 if (f_alt) 1234 flags |= NTOS_SHOWBASE; 1235 u.str = iob_int2str(ap, size, mdb.m_radix, flags, 1236 &zero, &val); 1237 break; 1238 1239 case 's': 1240 u.str = VA_PTRARG(ap); 1241 if (u.str == NULL) 1242 u.str = "<NULL>"; /* Be forgiving of NULL */ 1243 break; 1244 1245 case 't': 1246 if (width != 0) { 1247 while (width-- > 0) 1248 mdb_iob_tab(iob); 1249 } else 1250 mdb_iob_tab(iob); 1251 1252 format = ++p; 1253 continue; 1254 1255 case 'T': 1256 if (width != 0 && (iob->iob_nbytes % width) != 0) { 1257 size_t ots = iob->iob_tabstop; 1258 iob->iob_tabstop = width; 1259 mdb_iob_tab(iob); 1260 iob->iob_tabstop = ots; 1261 } 1262 format = ++p; 1263 continue; 1264 1265 case 'u': 1266 if (f_alt) 1267 flags |= NTOS_SHOWBASE; 1268 u.str = iob_int2str(ap, size, 10, 1269 flags | NTOS_UNSIGNED, &zero, &val); 1270 break; 1271 1272 case 'x': 1273 u.str = iob_int2str(ap, size, 16, NTOS_UNSIGNED, 1274 &zero, &val); 1275 1276 if (f_alt && !zero) { 1277 altstr = "0x"; 1278 altlen = 2; 1279 } 1280 break; 1281 1282 case 'X': 1283 u.str = iob_int2str(ap, size, 16, 1284 NTOS_UNSIGNED | NTOS_UPCASE, &zero, &val); 1285 1286 if (f_alt && !zero) { 1287 altstr = "0X"; 1288 altlen = 2; 1289 } 1290 break; 1291 1292 case 'Y': 1293 u.tm = VA_ARG(ap, time_t); 1294 u.str = iob_time2str(&u.tm); 1295 break; 1296 1297 case '<': 1298 /* 1299 * Used to turn attributes on (<b>), to turn them 1300 * off (</b>), or to print variables (<_var>). 1301 */ 1302 for (u.str = ++p; *p != '\0' && *p != '>'; p++) 1303 continue; 1304 1305 if (*p == '>') { 1306 size_t paramlen = p - u.str; 1307 1308 if (paramlen > 0) { 1309 if (*u.str == '_') { 1310 u.str = iob_getvar(u.str + 1, 1311 paramlen - 1); 1312 break; 1313 } else { 1314 (void) iob_setattr(iob, u.str, 1315 paramlen); 1316 } 1317 } 1318 1319 p++; 1320 } 1321 1322 format = p; 1323 continue; 1324 1325 case '*': 1326 width = (size_t)(uint_t)VA_ARG(ap, int); 1327 goto fmt_switch; 1328 1329 case '%': 1330 u.str = "%"; 1331 break; 1332 1333 case '?': 1334 width = sizeof (uintptr_t) * 2; 1335 goto fmt_switch; 1336 1337 case '#': 1338 f_alt = TRUE; 1339 goto fmt_switch; 1340 1341 case '+': 1342 flags |= NTOS_SIGNPOS; 1343 goto fmt_switch; 1344 1345 case '-': 1346 f_left = TRUE; 1347 goto fmt_switch; 1348 1349 default: 1350 c[0] = p[0]; 1351 u.str = c; 1352 } 1353 1354 len = u.str != NULL ? strlen(u.str) : 0; 1355 1356 if (len + altlen > width) 1357 width = len + altlen; 1358 1359 /* 1360 * If the string and the option altstr won't fit on this line 1361 * and auto-wrap is set (default), skip to the next line. 1362 */ 1363 if (IOB_WRAPNOW(iob, width)) 1364 mdb_iob_nl(iob); 1365 1366 /* 1367 * Optionally add whitespace or zeroes prefixing the value if 1368 * we haven't filled the minimum width and we're right-aligned. 1369 */ 1370 if (len < (width - altlen) && f_left == FALSE) { 1371 mdb_iob_fill(iob, f_zfill ? '0' : ' ', 1372 width - altlen - len); 1373 } 1374 1375 /* 1376 * Print the alternate string if it's a prefix, and then 1377 * print the value string itself. 1378 */ 1379 if (altstr != NULL && f_altsuff == FALSE) 1380 mdb_iob_nputs(iob, altstr, altlen); 1381 if (len != 0) 1382 mdb_iob_nputs(iob, u.str, len); 1383 1384 /* 1385 * If we have an alternate string and it's a suffix, print it. 1386 */ 1387 if (altstr != NULL && f_altsuff == TRUE) 1388 mdb_iob_nputs(iob, altstr, altlen); 1389 1390 /* 1391 * Finally, if we haven't filled the field width and we're 1392 * left-aligned, pad out the rest with whitespace. 1393 */ 1394 if ((len + altlen) < width && f_left == TRUE) 1395 mdb_iob_ws(iob, width - altlen - len); 1396 1397 format = (*p != '\0') ? ++p : p; 1398 } 1399 1400 /* 1401 * If there's anything left in the format string, output it now 1402 */ 1403 if (*format != '\0') { 1404 len = strlen(format); 1405 if (IOB_WRAPNOW(iob, len) && *format != '\n') 1406 mdb_iob_nl(iob); 1407 mdb_iob_nputs(iob, format, len); 1408 } 1409 } 1410 1411 void 1412 mdb_iob_vprintf(mdb_iob_t *iob, const char *format, va_list alist) 1413 { 1414 varglist_t ap = { VAT_VARARGS }; 1415 va_copy(ap.val_valist, alist); 1416 iob_doprnt(iob, format, &ap); 1417 } 1418 1419 void 1420 mdb_iob_aprintf(mdb_iob_t *iob, const char *format, const mdb_arg_t *argv) 1421 { 1422 varglist_t ap = { VAT_ARGVEC }; 1423 ap.val_argv = argv; 1424 iob_doprnt(iob, format, &ap); 1425 } 1426 1427 void 1428 mdb_iob_printf(mdb_iob_t *iob, const char *format, ...) 1429 { 1430 va_list alist; 1431 1432 va_start(alist, format); 1433 mdb_iob_vprintf(iob, format, alist); 1434 va_end(alist); 1435 } 1436 1437 /* 1438 * In order to handle the sprintf family of functions, we define a special 1439 * i/o backend known as a "sprintf buf" (or spbuf for short). This back end 1440 * provides an IOP_WRITE entry point that concatenates each buffer sent from 1441 * mdb_iob_flush() onto the caller's buffer until the caller's buffer is 1442 * exhausted. We also keep an absolute count of how many bytes were sent to 1443 * this function during the lifetime of the snprintf call. This allows us 1444 * to provide the ability to (1) return the total size required for the given 1445 * format string and argument list, and (2) support a call to snprintf with a 1446 * NULL buffer argument with no special case code elsewhere. 1447 */ 1448 static ssize_t 1449 spbuf_write(mdb_io_t *io, const void *buf, size_t buflen) 1450 { 1451 spbuf_t *spb = io->io_data; 1452 1453 if (spb->spb_bufsiz != 0) { 1454 size_t n = MIN(spb->spb_bufsiz, buflen); 1455 bcopy(buf, spb->spb_buf, n); 1456 spb->spb_buf += n; 1457 spb->spb_bufsiz -= n; 1458 } 1459 1460 spb->spb_total += buflen; 1461 return (buflen); 1462 } 1463 1464 static const mdb_io_ops_t spbuf_ops = { 1465 no_io_read, 1466 spbuf_write, 1467 no_io_seek, 1468 no_io_ctl, 1469 no_io_close, 1470 no_io_name, 1471 no_io_link, 1472 no_io_unlink, 1473 no_io_setattr, 1474 no_io_suspend, 1475 no_io_resume 1476 }; 1477 1478 /* 1479 * The iob_spb_create function initializes an iob suitable for snprintf calls, 1480 * a spbuf i/o backend, and the spbuf private data, and then glues these 1481 * objects together. The caller (either vsnprintf or asnprintf below) is 1482 * expected to have allocated the various structures on their stack. 1483 */ 1484 static void 1485 iob_spb_create(mdb_iob_t *iob, char *iob_buf, size_t iob_len, 1486 mdb_io_t *io, spbuf_t *spb, char *spb_buf, size_t spb_len) 1487 { 1488 spb->spb_buf = spb_buf; 1489 spb->spb_bufsiz = spb_len; 1490 spb->spb_total = 0; 1491 1492 io->io_ops = &spbuf_ops; 1493 io->io_data = spb; 1494 io->io_next = NULL; 1495 io->io_refcnt = 1; 1496 1497 iob->iob_buf = iob_buf; 1498 iob->iob_bufsiz = iob_len; 1499 iob->iob_bufp = iob_buf; 1500 iob->iob_nbytes = 0; 1501 iob->iob_nlines = 0; 1502 iob->iob_lineno = 1; 1503 iob->iob_rows = MDB_IOB_DEFROWS; 1504 iob->iob_cols = iob_len; 1505 iob->iob_tabstop = MDB_IOB_DEFTAB; 1506 iob->iob_margin = MDB_IOB_DEFMARGIN; 1507 iob->iob_flags = MDB_IOB_WRONLY; 1508 iob->iob_iop = io; 1509 iob->iob_pgp = NULL; 1510 iob->iob_next = NULL; 1511 } 1512 1513 /*ARGSUSED*/ 1514 ssize_t 1515 null_io_write(mdb_io_t *io, const void *buf, size_t nbytes) 1516 { 1517 return (nbytes); 1518 } 1519 1520 static const mdb_io_ops_t null_ops = { 1521 no_io_read, 1522 null_io_write, 1523 no_io_seek, 1524 no_io_ctl, 1525 no_io_close, 1526 no_io_name, 1527 no_io_link, 1528 no_io_unlink, 1529 no_io_setattr, 1530 no_io_suspend, 1531 no_io_resume 1532 }; 1533 1534 mdb_io_t * 1535 mdb_nullio_create(void) 1536 { 1537 static mdb_io_t null_io = { 1538 &null_ops, 1539 NULL, 1540 NULL, 1541 1 1542 }; 1543 1544 return (&null_io); 1545 } 1546 1547 size_t 1548 mdb_iob_vsnprintf(char *buf, size_t nbytes, const char *format, va_list alist) 1549 { 1550 varglist_t ap = { VAT_VARARGS }; 1551 char iob_buf[64]; 1552 mdb_iob_t iob; 1553 mdb_io_t io; 1554 spbuf_t spb; 1555 1556 ASSERT(buf != NULL || nbytes == 0); 1557 iob_spb_create(&iob, iob_buf, sizeof (iob_buf), &io, &spb, buf, nbytes); 1558 va_copy(ap.val_valist, alist); 1559 iob_doprnt(&iob, format, &ap); 1560 mdb_iob_flush(&iob); 1561 1562 if (spb.spb_bufsiz != 0) 1563 *spb.spb_buf = '\0'; 1564 else if (buf != NULL && nbytes > 0) 1565 *--spb.spb_buf = '\0'; 1566 1567 return (spb.spb_total); 1568 } 1569 1570 size_t 1571 mdb_iob_asnprintf(char *buf, size_t nbytes, const char *format, 1572 const mdb_arg_t *argv) 1573 { 1574 varglist_t ap = { VAT_ARGVEC }; 1575 char iob_buf[64]; 1576 mdb_iob_t iob; 1577 mdb_io_t io; 1578 spbuf_t spb; 1579 1580 ASSERT(buf != NULL || nbytes == 0); 1581 iob_spb_create(&iob, iob_buf, sizeof (iob_buf), &io, &spb, buf, nbytes); 1582 ap.val_argv = argv; 1583 iob_doprnt(&iob, format, &ap); 1584 mdb_iob_flush(&iob); 1585 1586 if (spb.spb_bufsiz != 0) 1587 *spb.spb_buf = '\0'; 1588 else if (buf != NULL && nbytes > 0) 1589 *--spb.spb_buf = '\0'; 1590 1591 return (spb.spb_total); 1592 } 1593 1594 /*PRINTFLIKE3*/ 1595 size_t 1596 mdb_iob_snprintf(char *buf, size_t nbytes, const char *format, ...) 1597 { 1598 va_list alist; 1599 1600 va_start(alist, format); 1601 nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist); 1602 va_end(alist); 1603 1604 return (nbytes); 1605 } 1606 1607 void 1608 mdb_iob_nputs(mdb_iob_t *iob, const char *s, size_t nbytes) 1609 { 1610 size_t m, n, nleft = nbytes; 1611 const char *p, *q = s; 1612 1613 ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 1614 1615 if (nbytes == 0) 1616 return; /* Return immediately if there is no work to do */ 1617 1618 /* 1619 * If the string contains embedded newlines or tabs, invoke ourself 1620 * recursively for each string component, followed by a call to the 1621 * newline or tab routine. This insures that strings with these 1622 * characters obey our wrapping and indenting rules, and that strings 1623 * with embedded newlines are flushed after each newline, allowing 1624 * the output pager to take over if it is enabled. 1625 */ 1626 while ((p = strnpbrk(q, "\t\n", nleft)) != NULL) { 1627 if (p > q) 1628 mdb_iob_nputs(iob, q, (size_t)(p - q)); 1629 1630 if (*p == '\t') 1631 mdb_iob_tab(iob); 1632 else 1633 mdb_iob_nl(iob); 1634 1635 nleft -= (size_t)(p - q) + 1; /* Update byte count */ 1636 q = p + 1; /* Advance past delimiter */ 1637 } 1638 1639 /* 1640 * For a given string component, we determine how many bytes (n) we can 1641 * copy into our buffer (limited by either cols or bufsiz depending 1642 * on whether AUTOWRAP is on), copy a chunk into the buffer, and 1643 * flush the buffer if we reach the end of a line. 1644 */ 1645 while (nleft != 0) { 1646 if (iob->iob_flags & MDB_IOB_AUTOWRAP) { 1647 ASSERT(iob->iob_cols >= iob->iob_nbytes); 1648 n = iob->iob_cols - iob->iob_nbytes; 1649 } else { 1650 ASSERT(iob->iob_bufsiz >= iob->iob_nbytes); 1651 n = iob->iob_bufsiz - iob->iob_nbytes; 1652 } 1653 1654 m = MIN(nleft, n); /* copy at most n bytes in this pass */ 1655 1656 bcopy(q, iob->iob_bufp, m); 1657 nleft -= m; 1658 q += m; 1659 1660 iob->iob_bufp += m; 1661 iob->iob_nbytes += m; 1662 1663 if (m == n && nleft != 0) { 1664 if (iob->iob_flags & MDB_IOB_AUTOWRAP) 1665 mdb_iob_nl(iob); 1666 else 1667 mdb_iob_flush(iob); 1668 } 1669 } 1670 } 1671 1672 void 1673 mdb_iob_puts(mdb_iob_t *iob, const char *s) 1674 { 1675 mdb_iob_nputs(iob, s, strlen(s)); 1676 } 1677 1678 void 1679 mdb_iob_putc(mdb_iob_t *iob, int c) 1680 { 1681 mdb_iob_fill(iob, c, 1); 1682 } 1683 1684 void 1685 mdb_iob_tab(mdb_iob_t *iob) 1686 { 1687 ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 1688 1689 if (iob->iob_tabstop != 0) { 1690 /* 1691 * Round up to the next multiple of the tabstop. If this puts 1692 * us off the end of the line, just insert a newline; otherwise 1693 * insert sufficient whitespace to reach position n. 1694 */ 1695 size_t n = (iob->iob_nbytes + iob->iob_tabstop) / 1696 iob->iob_tabstop * iob->iob_tabstop; 1697 1698 if (n < iob->iob_cols) 1699 mdb_iob_fill(iob, ' ', n - iob->iob_nbytes); 1700 else 1701 mdb_iob_nl(iob); 1702 } 1703 } 1704 1705 void 1706 mdb_iob_fill(mdb_iob_t *iob, int c, size_t nfill) 1707 { 1708 size_t i, m, n; 1709 1710 ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 1711 1712 while (nfill != 0) { 1713 if (iob->iob_flags & MDB_IOB_AUTOWRAP) { 1714 ASSERT(iob->iob_cols >= iob->iob_nbytes); 1715 n = iob->iob_cols - iob->iob_nbytes; 1716 } else { 1717 ASSERT(iob->iob_bufsiz >= iob->iob_nbytes); 1718 n = iob->iob_bufsiz - iob->iob_nbytes; 1719 } 1720 1721 m = MIN(nfill, n); /* fill at most n bytes in this pass */ 1722 1723 for (i = 0; i < m; i++) 1724 *iob->iob_bufp++ = (char)c; 1725 1726 iob->iob_nbytes += m; 1727 nfill -= m; 1728 1729 if (m == n && nfill != 0) { 1730 if (iob->iob_flags & MDB_IOB_AUTOWRAP) 1731 mdb_iob_nl(iob); 1732 else 1733 mdb_iob_flush(iob); 1734 } 1735 } 1736 } 1737 1738 void 1739 mdb_iob_ws(mdb_iob_t *iob, size_t n) 1740 { 1741 if (iob->iob_nbytes + n < iob->iob_cols) 1742 mdb_iob_fill(iob, ' ', n); 1743 else 1744 mdb_iob_nl(iob); 1745 } 1746 1747 void 1748 mdb_iob_nl(mdb_iob_t *iob) 1749 { 1750 ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 1751 1752 if (iob->iob_nbytes == iob->iob_bufsiz) 1753 mdb_iob_flush(iob); 1754 1755 *iob->iob_bufp++ = '\n'; 1756 iob->iob_nbytes++; 1757 1758 mdb_iob_flush(iob); 1759 } 1760 1761 ssize_t 1762 mdb_iob_ngets(mdb_iob_t *iob, char *buf, size_t n) 1763 { 1764 ssize_t resid = n - 1; 1765 ssize_t len; 1766 int c; 1767 1768 if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_EOF)) 1769 return (EOF); /* can't gets a write buf or a read buf at EOF */ 1770 1771 if (n == 0) 1772 return (0); /* we need room for a terminating \0 */ 1773 1774 while (resid != 0) { 1775 if (iob->iob_nbytes == 0 && iob_read(iob, iob->iob_iop) <= 0) 1776 goto done; /* failed to refill buffer */ 1777 1778 for (len = MIN(iob->iob_nbytes, resid); len != 0; len--) { 1779 c = *iob->iob_bufp++; 1780 iob->iob_nbytes--; 1781 1782 if (c == EOF || c == '\n') 1783 goto done; 1784 1785 *buf++ = (char)c; 1786 resid--; 1787 } 1788 } 1789 done: 1790 *buf = '\0'; 1791 return (n - resid - 1); 1792 } 1793 1794 int 1795 mdb_iob_getc(mdb_iob_t *iob) 1796 { 1797 int c; 1798 1799 if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_EOF | MDB_IOB_ERR)) 1800 return (EOF); /* can't getc if write-only, EOF, or error bit */ 1801 1802 if (iob->iob_nbytes == 0 && iob_read(iob, iob->iob_iop) <= 0) 1803 return (EOF); /* failed to refill buffer */ 1804 1805 c = (uchar_t)*iob->iob_bufp++; 1806 iob->iob_nbytes--; 1807 1808 return (c); 1809 } 1810 1811 int 1812 mdb_iob_ungetc(mdb_iob_t *iob, int c) 1813 { 1814 if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_ERR)) 1815 return (EOF); /* can't ungetc if write-only or error bit set */ 1816 1817 if (c == EOF || iob->iob_nbytes == iob->iob_bufsiz) 1818 return (EOF); /* can't ungetc EOF, or ungetc if buffer full */ 1819 1820 *--iob->iob_bufp = (char)c; 1821 iob->iob_nbytes++; 1822 iob->iob_flags &= ~MDB_IOB_EOF; 1823 1824 return (c); 1825 } 1826 1827 int 1828 mdb_iob_eof(mdb_iob_t *iob) 1829 { 1830 return ((iob->iob_flags & (MDB_IOB_RDONLY | MDB_IOB_EOF)) == 1831 (MDB_IOB_RDONLY | MDB_IOB_EOF)); 1832 } 1833 1834 int 1835 mdb_iob_err(mdb_iob_t *iob) 1836 { 1837 return ((iob->iob_flags & MDB_IOB_ERR) == MDB_IOB_ERR); 1838 } 1839 1840 ssize_t 1841 mdb_iob_read(mdb_iob_t *iob, void *buf, size_t n) 1842 { 1843 ssize_t resid = n; 1844 ssize_t len; 1845 1846 if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_EOF | MDB_IOB_ERR)) 1847 return (0); /* can't read if write-only, eof, or error */ 1848 1849 while (resid != 0) { 1850 if (iob->iob_nbytes == 0 && iob_read(iob, iob->iob_iop) <= 0) 1851 break; /* failed to refill buffer */ 1852 1853 len = MIN(resid, iob->iob_nbytes); 1854 bcopy(iob->iob_bufp, buf, len); 1855 1856 iob->iob_bufp += len; 1857 iob->iob_nbytes -= len; 1858 1859 buf = (char *)buf + len; 1860 resid -= len; 1861 } 1862 1863 return (n - resid); 1864 } 1865 1866 /* 1867 * For now, all binary writes are performed unbuffered. This has the 1868 * side effect that the pager will not be triggered by mdb_iob_write. 1869 */ 1870 ssize_t 1871 mdb_iob_write(mdb_iob_t *iob, const void *buf, size_t n) 1872 { 1873 ssize_t ret; 1874 1875 if (iob->iob_flags & MDB_IOB_ERR) 1876 return (set_errno(EIO)); 1877 if (iob->iob_flags & MDB_IOB_RDONLY) 1878 return (set_errno(EMDB_IORO)); 1879 1880 mdb_iob_flush(iob); 1881 ret = iob_write(iob, iob->iob_iop, buf, n); 1882 1883 if (ret < 0 && iob == mdb.m_out) 1884 longjmp(mdb.m_frame->f_pcb, MDB_ERR_OUTPUT); 1885 1886 return (ret); 1887 } 1888 1889 int 1890 mdb_iob_ctl(mdb_iob_t *iob, int req, void *arg) 1891 { 1892 return (IOP_CTL(iob->iob_iop, req, arg)); 1893 } 1894 1895 const char * 1896 mdb_iob_name(mdb_iob_t *iob) 1897 { 1898 if (iob == NULL) 1899 return ("<NULL>"); 1900 1901 return (IOP_NAME(iob->iob_iop)); 1902 } 1903 1904 size_t 1905 mdb_iob_lineno(mdb_iob_t *iob) 1906 { 1907 return (iob->iob_lineno); 1908 } 1909 1910 size_t 1911 mdb_iob_gettabstop(mdb_iob_t *iob) 1912 { 1913 return (iob->iob_tabstop); 1914 } 1915 1916 size_t 1917 mdb_iob_getmargin(mdb_iob_t *iob) 1918 { 1919 return (iob->iob_margin); 1920 } 1921 1922 mdb_io_t * 1923 mdb_io_hold(mdb_io_t *io) 1924 { 1925 io->io_refcnt++; 1926 return (io); 1927 } 1928 1929 void 1930 mdb_io_rele(mdb_io_t *io) 1931 { 1932 ASSERT(io->io_refcnt != 0); 1933 1934 if (--io->io_refcnt == 0) { 1935 IOP_CLOSE(io); 1936 mdb_free(io, sizeof (mdb_io_t)); 1937 } 1938 } 1939 1940 void 1941 mdb_io_destroy(mdb_io_t *io) 1942 { 1943 ASSERT(io->io_refcnt == 0); 1944 IOP_CLOSE(io); 1945 mdb_free(io, sizeof (mdb_io_t)); 1946 } 1947 1948 void 1949 mdb_iob_stack_create(mdb_iob_stack_t *stk) 1950 { 1951 stk->stk_top = NULL; 1952 stk->stk_size = 0; 1953 } 1954 1955 void 1956 mdb_iob_stack_destroy(mdb_iob_stack_t *stk) 1957 { 1958 mdb_iob_t *top, *ntop; 1959 1960 for (top = stk->stk_top; top != NULL; top = ntop) { 1961 ntop = top->iob_next; 1962 mdb_iob_destroy(top); 1963 } 1964 } 1965 1966 void 1967 mdb_iob_stack_push(mdb_iob_stack_t *stk, mdb_iob_t *iob, size_t lineno) 1968 { 1969 iob->iob_lineno = lineno; 1970 iob->iob_next = stk->stk_top; 1971 stk->stk_top = iob; 1972 stk->stk_size++; 1973 yylineno = 1; 1974 } 1975 1976 mdb_iob_t * 1977 mdb_iob_stack_pop(mdb_iob_stack_t *stk) 1978 { 1979 mdb_iob_t *top = stk->stk_top; 1980 1981 ASSERT(top != NULL); 1982 1983 stk->stk_top = top->iob_next; 1984 top->iob_next = NULL; 1985 stk->stk_size--; 1986 1987 return (top); 1988 } 1989 1990 size_t 1991 mdb_iob_stack_size(mdb_iob_stack_t *stk) 1992 { 1993 return (stk->stk_size); 1994 } 1995 1996 /* 1997 * Stub functions for i/o backend implementors: these stubs either act as 1998 * pass-through no-ops or return ENOTSUP as appropriate. 1999 */ 2000 ssize_t 2001 no_io_read(mdb_io_t *io, void *buf, size_t nbytes) 2002 { 2003 if (io->io_next != NULL) 2004 return (IOP_READ(io->io_next, buf, nbytes)); 2005 2006 return (set_errno(EMDB_IOWO)); 2007 } 2008 2009 ssize_t 2010 no_io_write(mdb_io_t *io, const void *buf, size_t nbytes) 2011 { 2012 if (io->io_next != NULL) 2013 return (IOP_WRITE(io->io_next, buf, nbytes)); 2014 2015 return (set_errno(EMDB_IORO)); 2016 } 2017 2018 off64_t 2019 no_io_seek(mdb_io_t *io, off64_t offset, int whence) 2020 { 2021 if (io->io_next != NULL) 2022 return (IOP_SEEK(io->io_next, offset, whence)); 2023 2024 return (set_errno(ENOTSUP)); 2025 } 2026 2027 int 2028 no_io_ctl(mdb_io_t *io, int req, void *arg) 2029 { 2030 if (io->io_next != NULL) 2031 return (IOP_CTL(io->io_next, req, arg)); 2032 2033 return (set_errno(ENOTSUP)); 2034 } 2035 2036 /*ARGSUSED*/ 2037 void 2038 no_io_close(mdb_io_t *io) 2039 { 2040 /* 2041 * Note that we do not propagate IOP_CLOSE down the io stack. IOP_CLOSE should 2042 * only be called by mdb_io_rele when an io's reference count has gone to zero. 2043 */ 2044 } 2045 2046 const char * 2047 no_io_name(mdb_io_t *io) 2048 { 2049 if (io->io_next != NULL) 2050 return (IOP_NAME(io->io_next)); 2051 2052 return ("(anonymous)"); 2053 } 2054 2055 void 2056 no_io_link(mdb_io_t *io, mdb_iob_t *iob) 2057 { 2058 if (io->io_next != NULL) 2059 IOP_LINK(io->io_next, iob); 2060 } 2061 2062 void 2063 no_io_unlink(mdb_io_t *io, mdb_iob_t *iob) 2064 { 2065 if (io->io_next != NULL) 2066 IOP_UNLINK(io->io_next, iob); 2067 } 2068 2069 int 2070 no_io_setattr(mdb_io_t *io, int req, uint_t attrs) 2071 { 2072 if (io->io_next != NULL) 2073 return (IOP_SETATTR(io->io_next, req, attrs)); 2074 2075 return (set_errno(ENOTSUP)); 2076 } 2077 2078 void 2079 no_io_suspend(mdb_io_t *io) 2080 { 2081 if (io->io_next != NULL) 2082 IOP_SUSPEND(io->io_next); 2083 } 2084 2085 void 2086 no_io_resume(mdb_io_t *io) 2087 { 2088 if (io->io_next != NULL) 2089 IOP_RESUME(io->io_next); 2090 } 2091 2092 /* 2093 * Iterate over the varargs. The first item indicates the mode: 2094 * MDB_TBL_PRNT 2095 * pull out the next vararg as a const char * and pass it and the 2096 * remaining varargs to iob_doprnt; if we want to print the column, 2097 * direct the output to mdb.m_out otherwise direct it to mdb.m_null 2098 * 2099 * MDB_TBL_FUNC 2100 * pull out the next vararg as type mdb_table_print_f and the 2101 * following one as a void * argument to the function; call the 2102 * function with the given argument if we want to print the column 2103 * 2104 * The second item indicates the flag; if the flag is set in the flags 2105 * argument, then the column is printed. A flag value of 0 indicates 2106 * that the column should always be printed. 2107 */ 2108 void 2109 mdb_table_print(uint_t flags, const char *delimeter, ...) 2110 { 2111 va_list alist; 2112 uint_t flg; 2113 uint_t type; 2114 const char *fmt; 2115 mdb_table_print_f *func; 2116 void *arg; 2117 mdb_iob_t *out; 2118 mdb_bool_t first = TRUE; 2119 mdb_bool_t print; 2120 2121 va_start(alist, delimeter); 2122 2123 while ((type = va_arg(alist, uint_t)) != MDB_TBL_DONE) { 2124 flg = va_arg(alist, uint_t); 2125 2126 print = flg == 0 || (flg & flags) != 0; 2127 2128 if (print) { 2129 if (first) 2130 first = FALSE; 2131 else 2132 mdb_printf("%s", delimeter); 2133 } 2134 2135 switch (type) { 2136 case MDB_TBL_PRNT: { 2137 varglist_t ap = { VAT_VARARGS }; 2138 fmt = va_arg(alist, const char *); 2139 out = print ? mdb.m_out : mdb.m_null; 2140 va_copy(ap.val_valist, alist); 2141 iob_doprnt(out, fmt, &ap); 2142 va_end(alist); 2143 va_copy(alist, ap.val_valist); 2144 break; 2145 } 2146 2147 case MDB_TBL_FUNC: 2148 func = va_arg(alist, mdb_table_print_f *); 2149 arg = va_arg(alist, void *); 2150 2151 if (print) 2152 func(arg); 2153 2154 break; 2155 2156 default: 2157 warn("bad format type %x\n", type); 2158 break; 2159 } 2160 } 2161 2162 va_end(alist); 2163 } 2164