17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*a727d47aSjwadams * Common Development and Distribution License (the "License"). 6*a727d47aSjwadams * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*a727d47aSjwadams * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * MDB uses its own enhanced standard i/o mechanism for all input and output. 307c478bd9Sstevel@tonic-gate * This file provides the underpinnings of this mechanism, including the 317c478bd9Sstevel@tonic-gate * printf-style formatting code, the output pager, and APIs for raw input 327c478bd9Sstevel@tonic-gate * and output. This mechanism is used throughout the debugger for everything 337c478bd9Sstevel@tonic-gate * from simple sprintf and printf-style formatting, to input to the lexer 347c478bd9Sstevel@tonic-gate * and parser, to raw file i/o for reading ELF files. In general, we divide 357c478bd9Sstevel@tonic-gate * our i/o implementation into two parts: 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * (1) An i/o buffer (mdb_iob_t) provides buffered read or write capabilities, 387c478bd9Sstevel@tonic-gate * as well as access to formatting and the ability to invoke a pager. The 397c478bd9Sstevel@tonic-gate * buffer is constructed explicitly for use in either reading or writing; it 407c478bd9Sstevel@tonic-gate * may not be used for both simultaneously. 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * (2) Each i/o buffer is associated with an underlying i/o backend (mdb_io_t). 437c478bd9Sstevel@tonic-gate * The backend provides, through an ops-vector, equivalents for the standard 447c478bd9Sstevel@tonic-gate * read, write, lseek, ioctl, and close operations. In addition, the backend 457c478bd9Sstevel@tonic-gate * can provide an IOP_NAME entry point for returning a name for the backend, 467c478bd9Sstevel@tonic-gate * IOP_LINK and IOP_UNLINK entry points that are called when the backend is 477c478bd9Sstevel@tonic-gate * connected or disconnected from an mdb_iob_t, and an IOP_SETATTR entry point 487c478bd9Sstevel@tonic-gate * for manipulating terminal attributes. 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * The i/o objects themselves are reference counted so that more than one i/o 517c478bd9Sstevel@tonic-gate * buffer may make use of the same i/o backend. In addition, each buffer 527c478bd9Sstevel@tonic-gate * provides the ability to push or pop backends to interpose on input or output 537c478bd9Sstevel@tonic-gate * behavior. We make use of this, for example, to implement interactive 547c478bd9Sstevel@tonic-gate * session logging. Normally, the stdout iob has a backend that is either 557c478bd9Sstevel@tonic-gate * file descriptor 1, or a terminal i/o backend associated with the tty. 567c478bd9Sstevel@tonic-gate * However, we can push a log i/o backend on top that multiplexes stdout to 577c478bd9Sstevel@tonic-gate * the original back-end and another backend that writes to a log file. The 587c478bd9Sstevel@tonic-gate * use of i/o backends is also used for simplifying tasks such as making 597c478bd9Sstevel@tonic-gate * lex and yacc read from strings for mdb_eval(), and making our ELF file 607c478bd9Sstevel@tonic-gate * processing code read executable "files" from a crash dump via kvm_uread. 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * Additionally, the formatting code provides auto-wrap and indent facilities 637c478bd9Sstevel@tonic-gate * that are necessary for compatibility with adb macro formatting. In auto- 647c478bd9Sstevel@tonic-gate * wrap mode, the formatting code examines each new chunk of output to determine 657c478bd9Sstevel@tonic-gate * if it will fit on the current line. If not, instead of having the chunk 667c478bd9Sstevel@tonic-gate * divided between the current line of output and the next, the auto-wrap 677c478bd9Sstevel@tonic-gate * code will automatically output a newline, auto-indent the next line, 687c478bd9Sstevel@tonic-gate * and then continue. Auto-indent is implemented by simply prepending a number 697c478bd9Sstevel@tonic-gate * of blanks equal to iob_margin to the start of each line. The margin is 707c478bd9Sstevel@tonic-gate * inserted when the iob is created, and following each flush of the buffer. 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <sys/types.h> 747c478bd9Sstevel@tonic-gate #include <sys/termios.h> 757c478bd9Sstevel@tonic-gate #include <stdarg.h> 767c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 777c478bd9Sstevel@tonic-gate #include <sys/socket.h> 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #include <mdb/mdb_types.h> 807c478bd9Sstevel@tonic-gate #include <mdb/mdb_argvec.h> 817c478bd9Sstevel@tonic-gate #include <mdb/mdb_stdlib.h> 827c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h> 837c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h> 847c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h> 857c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 867c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h> 877c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 887c478bd9Sstevel@tonic-gate #include <mdb/mdb_demangle.h> 897c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 907c478bd9Sstevel@tonic-gate #include <mdb/mdb_nv.h> 917c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h> 927c478bd9Sstevel@tonic-gate #include <mdb/mdb_lex.h> 937c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * Define list of possible integer sizes for conversion routines: 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate typedef enum { 997c478bd9Sstevel@tonic-gate SZ_SHORT, /* format %h? */ 1007c478bd9Sstevel@tonic-gate SZ_INT, /* format %? */ 1017c478bd9Sstevel@tonic-gate SZ_LONG, /* format %l? */ 1027c478bd9Sstevel@tonic-gate SZ_LONGLONG /* format %ll? */ 1037c478bd9Sstevel@tonic-gate } intsize_t; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * The iob snprintf family of functions makes use of a special "sprintf 1077c478bd9Sstevel@tonic-gate * buffer" i/o backend in order to provide the appropriate snprintf semantics. 1087c478bd9Sstevel@tonic-gate * This structure is maintained as the backend-specific private storage, 1097c478bd9Sstevel@tonic-gate * and its use is described in more detail below (see spbuf_write()). 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate typedef struct { 1127c478bd9Sstevel@tonic-gate char *spb_buf; /* pointer to underlying buffer */ 1137c478bd9Sstevel@tonic-gate size_t spb_bufsiz; /* length of underlying buffer */ 1147c478bd9Sstevel@tonic-gate size_t spb_total; /* total of all bytes passed via IOP_WRITE */ 1157c478bd9Sstevel@tonic-gate } spbuf_t; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * Define VA_ARG macro for grabbing the next datum to format for the printf 1197c478bd9Sstevel@tonic-gate * family of functions. We use VA_ARG so that we can support two kinds of 1207c478bd9Sstevel@tonic-gate * argument lists: the va_list type supplied by <stdarg.h> used for printf and 1217c478bd9Sstevel@tonic-gate * vprintf, and an array of mdb_arg_t structures, which we expect will be 1227c478bd9Sstevel@tonic-gate * either type STRING or IMMEDIATE. The vec_arg function takes care of 1237c478bd9Sstevel@tonic-gate * handling the mdb_arg_t case. 1247c478bd9Sstevel@tonic-gate */ 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate typedef enum { 1277c478bd9Sstevel@tonic-gate VAT_VARARGS, /* va_list is a va_list */ 1287c478bd9Sstevel@tonic-gate VAT_ARGVEC /* va_list is a const mdb_arg_t[] in disguise */ 1297c478bd9Sstevel@tonic-gate } vatype_t; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate typedef struct { 1327c478bd9Sstevel@tonic-gate vatype_t val_type; 1337c478bd9Sstevel@tonic-gate union { 1347c478bd9Sstevel@tonic-gate va_list _val_valist; 1357c478bd9Sstevel@tonic-gate const mdb_arg_t *_val_argv; 1367c478bd9Sstevel@tonic-gate } _val_u; 1377c478bd9Sstevel@tonic-gate } varglist_t; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate #define val_valist _val_u._val_valist 1407c478bd9Sstevel@tonic-gate #define val_argv _val_u._val_argv 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate #define VA_ARG(ap, type) ((ap->val_type == VAT_VARARGS) ? \ 1437c478bd9Sstevel@tonic-gate va_arg(ap->val_valist, type) : (type)vec_arg(&ap->val_argv)) 1447c478bd9Sstevel@tonic-gate #define VA_PTRARG(ap) ((ap->val_type == VAT_VARARGS) ? \ 1457c478bd9Sstevel@tonic-gate (void *)va_arg(ap->val_valist, uintptr_t) : \ 1467c478bd9Sstevel@tonic-gate (void *)(uintptr_t)vec_arg(&ap->val_argv)) 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Define macro for converting char constant to Ctrl-char equivalent: 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate #ifndef CTRL 1527c478bd9Sstevel@tonic-gate #define CTRL(c) ((c) & 0x01f) 1537c478bd9Sstevel@tonic-gate #endif 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 1567c478bd9Sstevel@tonic-gate * Define macro for determining if we should automatically wrap to the next 1577c478bd9Sstevel@tonic-gate * line of output, based on the amount of consumed buffer space and the 1587c478bd9Sstevel@tonic-gate * specified size of the next thing to be inserted (n). 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate #define IOB_WRAPNOW(iob, n) \ 1617c478bd9Sstevel@tonic-gate (((iob)->iob_flags & MDB_IOB_AUTOWRAP) && ((iob)->iob_nbytes != 0) && \ 1627c478bd9Sstevel@tonic-gate ((n) + (iob)->iob_nbytes > (iob)->iob_cols)) 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Define prompt string and string to erase prompt string for iob_pager 1667c478bd9Sstevel@tonic-gate * function, which is invoked if the pager is enabled on an i/o buffer 1677c478bd9Sstevel@tonic-gate * and we're about to print a line which would be the last on the screen. 1687c478bd9Sstevel@tonic-gate */ 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate static const char io_prompt[] = ">> More [<space>, <cr>, q, n, c, a] ? "; 1717c478bd9Sstevel@tonic-gate static const char io_perase[] = " "; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate static const char io_pbcksp[] = 1747c478bd9Sstevel@tonic-gate /*CSTYLED*/ 1757c478bd9Sstevel@tonic-gate "\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"; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static const size_t io_promptlen = sizeof (io_prompt) - 1; 1787c478bd9Sstevel@tonic-gate static const size_t io_peraselen = sizeof (io_perase) - 1; 1797c478bd9Sstevel@tonic-gate static const size_t io_pbcksplen = sizeof (io_pbcksp) - 1; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate static ssize_t 1827c478bd9Sstevel@tonic-gate iob_write(mdb_iob_t *iob, mdb_io_t *io, const void *buf, size_t n) 1837c478bd9Sstevel@tonic-gate { 1847c478bd9Sstevel@tonic-gate ssize_t resid = n; 1857c478bd9Sstevel@tonic-gate ssize_t len; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate while (resid != 0) { 1887c478bd9Sstevel@tonic-gate if ((len = IOP_WRITE(io, buf, resid)) <= 0) 1897c478bd9Sstevel@tonic-gate break; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate buf = (char *)buf + len; 1927c478bd9Sstevel@tonic-gate resid -= len; 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * Note that if we had a partial write before an error, we still want 1977c478bd9Sstevel@tonic-gate * to return the fact something was written. The caller will get an 1987c478bd9Sstevel@tonic-gate * error next time it tries to write anything. 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate if (resid == n && n != 0) { 2017c478bd9Sstevel@tonic-gate iob->iob_flags |= MDB_IOB_ERR; 2027c478bd9Sstevel@tonic-gate return (-1); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate return (n - resid); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate static ssize_t 2097c478bd9Sstevel@tonic-gate iob_read(mdb_iob_t *iob, mdb_io_t *io) 2107c478bd9Sstevel@tonic-gate { 2117c478bd9Sstevel@tonic-gate ssize_t len; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate ASSERT(iob->iob_nbytes == 0); 2147c478bd9Sstevel@tonic-gate len = IOP_READ(io, iob->iob_buf, iob->iob_bufsiz); 2157c478bd9Sstevel@tonic-gate iob->iob_bufp = &iob->iob_buf[0]; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate switch (len) { 2187c478bd9Sstevel@tonic-gate case -1: 2197c478bd9Sstevel@tonic-gate iob->iob_flags |= MDB_IOB_ERR; 2207c478bd9Sstevel@tonic-gate break; 2217c478bd9Sstevel@tonic-gate case 0: 2227c478bd9Sstevel@tonic-gate iob->iob_flags |= MDB_IOB_EOF; 2237c478bd9Sstevel@tonic-gate break; 2247c478bd9Sstevel@tonic-gate default: 2257c478bd9Sstevel@tonic-gate iob->iob_nbytes = len; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate return (len); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2327c478bd9Sstevel@tonic-gate static void 2337c478bd9Sstevel@tonic-gate iob_winch(int sig, siginfo_t *sip, ucontext_t *ucp, void *data) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate siglongjmp(*((sigjmp_buf *)data), sig); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate static int 2397c478bd9Sstevel@tonic-gate iob_pager(mdb_iob_t *iob) 2407c478bd9Sstevel@tonic-gate { 2417c478bd9Sstevel@tonic-gate int status = 0; 2427c478bd9Sstevel@tonic-gate sigjmp_buf env; 2437c478bd9Sstevel@tonic-gate uchar_t c; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate mdb_signal_f *termio_winch; 2467c478bd9Sstevel@tonic-gate void *termio_data; 2477c478bd9Sstevel@tonic-gate size_t old_rows; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (iob->iob_pgp == NULL || (iob->iob_flags & MDB_IOB_PGCONT)) 2507c478bd9Sstevel@tonic-gate return (0); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate termio_winch = mdb_signal_gethandler(SIGWINCH, &termio_data); 2537c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGWINCH, iob_winch, &env); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate if (sigsetjmp(env, 1) != 0) { 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * Reset the cursor back to column zero before printing a new 2587c478bd9Sstevel@tonic-gate * prompt, since its position is unreliable after a SIGWINCH. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate (void) iob_write(iob, iob->iob_pgp, "\r", sizeof (char)); 2617c478bd9Sstevel@tonic-gate old_rows = iob->iob_rows; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * If an existing SIGWINCH handler was present, call it. We 2657c478bd9Sstevel@tonic-gate * expect that this will be termio: the handler will read the 2667c478bd9Sstevel@tonic-gate * new window size, and then resize this iob appropriately. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate if (termio_winch != (mdb_signal_f *)NULL) 2697c478bd9Sstevel@tonic-gate termio_winch(SIGWINCH, NULL, NULL, termio_data); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* 2727c478bd9Sstevel@tonic-gate * If the window has increased in size, we treat this like a 2737c478bd9Sstevel@tonic-gate * request to fill out the new remainder of the page. 2747c478bd9Sstevel@tonic-gate */ 2757c478bd9Sstevel@tonic-gate if (iob->iob_rows > old_rows) { 2767c478bd9Sstevel@tonic-gate iob->iob_flags &= ~MDB_IOB_PGSINGLE; 2777c478bd9Sstevel@tonic-gate iob->iob_nlines = old_rows; 2787c478bd9Sstevel@tonic-gate status = 0; 2797c478bd9Sstevel@tonic-gate goto winch; 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate (void) iob_write(iob, iob->iob_pgp, io_prompt, io_promptlen); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate for (;;) { 2867c478bd9Sstevel@tonic-gate if (IOP_READ(iob->iob_pgp, &c, sizeof (c)) != sizeof (c)) { 2877c478bd9Sstevel@tonic-gate status = MDB_ERR_PAGER; 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate switch (c) { 2927c478bd9Sstevel@tonic-gate case 'N': 2937c478bd9Sstevel@tonic-gate case 'n': 2947c478bd9Sstevel@tonic-gate case '\n': 2957c478bd9Sstevel@tonic-gate case '\r': 2967c478bd9Sstevel@tonic-gate iob->iob_flags |= MDB_IOB_PGSINGLE; 2977c478bd9Sstevel@tonic-gate goto done; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate case CTRL('c'): 3007c478bd9Sstevel@tonic-gate case CTRL('\\'): 3017c478bd9Sstevel@tonic-gate case 'Q': 3027c478bd9Sstevel@tonic-gate case 'q': 3037c478bd9Sstevel@tonic-gate mdb_iob_discard(iob); 3047c478bd9Sstevel@tonic-gate status = MDB_ERR_PAGER; 3057c478bd9Sstevel@tonic-gate goto done; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate case 'A': 3087c478bd9Sstevel@tonic-gate case 'a': 3097c478bd9Sstevel@tonic-gate mdb_iob_discard(iob); 3107c478bd9Sstevel@tonic-gate status = MDB_ERR_ABORT; 3117c478bd9Sstevel@tonic-gate goto done; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate case 'C': 3147c478bd9Sstevel@tonic-gate case 'c': 3157c478bd9Sstevel@tonic-gate iob->iob_flags |= MDB_IOB_PGCONT; 3167c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate case ' ': 3197c478bd9Sstevel@tonic-gate iob->iob_flags &= ~MDB_IOB_PGSINGLE; 3207c478bd9Sstevel@tonic-gate goto done; 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate done: 3257c478bd9Sstevel@tonic-gate (void) iob_write(iob, iob->iob_pgp, io_pbcksp, io_pbcksplen); 3267c478bd9Sstevel@tonic-gate winch: 3277c478bd9Sstevel@tonic-gate (void) iob_write(iob, iob->iob_pgp, io_perase, io_peraselen); 3287c478bd9Sstevel@tonic-gate (void) iob_write(iob, iob->iob_pgp, io_pbcksp, io_pbcksplen); 3297c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGWINCH, termio_winch, termio_data); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate if ((iob->iob_flags & MDB_IOB_ERR) && status == 0) 3327c478bd9Sstevel@tonic-gate status = MDB_ERR_OUTPUT; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate return (status); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate static void 3387c478bd9Sstevel@tonic-gate iob_indent(mdb_iob_t *iob) 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate if (iob->iob_nbytes == 0 && iob->iob_margin != 0 && 3417c478bd9Sstevel@tonic-gate (iob->iob_flags & MDB_IOB_INDENT)) { 3427c478bd9Sstevel@tonic-gate size_t i; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate ASSERT(iob->iob_margin < iob->iob_cols); 3457c478bd9Sstevel@tonic-gate ASSERT(iob->iob_bufp == iob->iob_buf); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate for (i = 0; i < iob->iob_margin; i++) 3487c478bd9Sstevel@tonic-gate *iob->iob_bufp++ = ' '; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate iob->iob_nbytes = iob->iob_margin; 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate static void 3557c478bd9Sstevel@tonic-gate iob_unindent(mdb_iob_t *iob) 3567c478bd9Sstevel@tonic-gate { 3577c478bd9Sstevel@tonic-gate if (iob->iob_nbytes != 0 && iob->iob_nbytes == iob->iob_margin) { 3587c478bd9Sstevel@tonic-gate const char *p = iob->iob_buf; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate while (p < &iob->iob_buf[iob->iob_margin]) { 3617c478bd9Sstevel@tonic-gate if (*p++ != ' ') 3627c478bd9Sstevel@tonic-gate return; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate iob->iob_bufp = &iob->iob_buf[0]; 3667c478bd9Sstevel@tonic-gate iob->iob_nbytes = 0; 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate mdb_iob_t * 3717c478bd9Sstevel@tonic-gate mdb_iob_create(mdb_io_t *io, uint_t flags) 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate mdb_iob_t *iob = mdb_alloc(sizeof (mdb_iob_t), UM_SLEEP); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate iob->iob_buf = mdb_alloc(BUFSIZ, UM_SLEEP); 3767c478bd9Sstevel@tonic-gate iob->iob_bufsiz = BUFSIZ; 3777c478bd9Sstevel@tonic-gate iob->iob_bufp = &iob->iob_buf[0]; 3787c478bd9Sstevel@tonic-gate iob->iob_nbytes = 0; 3797c478bd9Sstevel@tonic-gate iob->iob_nlines = 0; 3807c478bd9Sstevel@tonic-gate iob->iob_lineno = 1; 3817c478bd9Sstevel@tonic-gate iob->iob_rows = MDB_IOB_DEFROWS; 3827c478bd9Sstevel@tonic-gate iob->iob_cols = MDB_IOB_DEFCOLS; 3837c478bd9Sstevel@tonic-gate iob->iob_tabstop = MDB_IOB_DEFTAB; 3847c478bd9Sstevel@tonic-gate iob->iob_margin = MDB_IOB_DEFMARGIN; 3857c478bd9Sstevel@tonic-gate iob->iob_flags = flags & ~(MDB_IOB_EOF|MDB_IOB_ERR) | MDB_IOB_AUTOWRAP; 3867c478bd9Sstevel@tonic-gate iob->iob_iop = mdb_io_hold(io); 3877c478bd9Sstevel@tonic-gate iob->iob_pgp = NULL; 3887c478bd9Sstevel@tonic-gate iob->iob_next = NULL; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate IOP_LINK(io, iob); 3917c478bd9Sstevel@tonic-gate iob_indent(iob); 3927c478bd9Sstevel@tonic-gate return (iob); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate void 3967c478bd9Sstevel@tonic-gate mdb_iob_pipe(mdb_iob_t **iobs, mdb_iobsvc_f *rdsvc, mdb_iobsvc_f *wrsvc) 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate mdb_io_t *pio = mdb_pipeio_create(rdsvc, wrsvc); 3997c478bd9Sstevel@tonic-gate int i; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate iobs[0] = mdb_iob_create(pio, MDB_IOB_RDONLY); 4027c478bd9Sstevel@tonic-gate iobs[1] = mdb_iob_create(pio, MDB_IOB_WRONLY); 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 4057c478bd9Sstevel@tonic-gate iobs[i]->iob_flags &= ~MDB_IOB_AUTOWRAP; 4067c478bd9Sstevel@tonic-gate iobs[i]->iob_cols = iobs[i]->iob_bufsiz; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate void 4117c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb_iob_t *iob) 4127c478bd9Sstevel@tonic-gate { 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * Don't flush a pipe, since it may cause a context swith when the 4157c478bd9Sstevel@tonic-gate * other side has already been destroyed. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate if (!mdb_iob_isapipe(iob)) 4187c478bd9Sstevel@tonic-gate mdb_iob_flush(iob); 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate if (iob->iob_pgp != NULL) 4217c478bd9Sstevel@tonic-gate mdb_io_rele(iob->iob_pgp); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate while (iob->iob_iop != NULL) { 4247c478bd9Sstevel@tonic-gate IOP_UNLINK(iob->iob_iop, iob); 4257c478bd9Sstevel@tonic-gate (void) mdb_iob_pop_io(iob); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate mdb_free(iob->iob_buf, iob->iob_bufsiz); 4297c478bd9Sstevel@tonic-gate mdb_free(iob, sizeof (mdb_iob_t)); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate void 4337c478bd9Sstevel@tonic-gate mdb_iob_discard(mdb_iob_t *iob) 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate iob->iob_bufp = &iob->iob_buf[0]; 4367c478bd9Sstevel@tonic-gate iob->iob_nbytes = 0; 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate void 4407c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb_iob_t *iob) 4417c478bd9Sstevel@tonic-gate { 4427c478bd9Sstevel@tonic-gate int pgerr = 0; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate if (iob->iob_nbytes == 0) 4457c478bd9Sstevel@tonic-gate return; /* Nothing to do if buffer is empty */ 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_WRONLY) { 4487c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_PGSINGLE) { 4497c478bd9Sstevel@tonic-gate iob->iob_flags &= ~MDB_IOB_PGSINGLE; 4507c478bd9Sstevel@tonic-gate iob->iob_nlines = 0; 4517c478bd9Sstevel@tonic-gate pgerr = iob_pager(iob); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate } else if (iob->iob_nlines >= iob->iob_rows - 1) { 4547c478bd9Sstevel@tonic-gate iob->iob_nlines = 0; 4557c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_PGENABLE) 4567c478bd9Sstevel@tonic-gate pgerr = iob_pager(iob); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate if (pgerr == 0) { 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * We only jump out of the dcmd on error if the iob is 4627c478bd9Sstevel@tonic-gate * m_out. Presumably, if a dcmd has opened a special 4637c478bd9Sstevel@tonic-gate * file and is writing to it, it will handle errors 4647c478bd9Sstevel@tonic-gate * properly. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate if (iob_write(iob, iob->iob_iop, iob->iob_buf, 4677c478bd9Sstevel@tonic-gate iob->iob_nbytes) < 0 && iob == mdb.m_out) 4687c478bd9Sstevel@tonic-gate pgerr = MDB_ERR_OUTPUT; 4697c478bd9Sstevel@tonic-gate iob->iob_nlines++; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate iob->iob_bufp = &iob->iob_buf[0]; 4747c478bd9Sstevel@tonic-gate iob->iob_nbytes = 0; 4757c478bd9Sstevel@tonic-gate iob_indent(iob); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (pgerr) 4787c478bd9Sstevel@tonic-gate longjmp(mdb.m_frame->f_pcb, pgerr); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate void 4827c478bd9Sstevel@tonic-gate mdb_iob_nlflush(mdb_iob_t *iob) 4837c478bd9Sstevel@tonic-gate { 4847c478bd9Sstevel@tonic-gate iob_unindent(iob); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (iob->iob_nbytes != 0) 4877c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 4887c478bd9Sstevel@tonic-gate else 4897c478bd9Sstevel@tonic-gate iob_indent(iob); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate void 4937c478bd9Sstevel@tonic-gate mdb_iob_push_io(mdb_iob_t *iob, mdb_io_t *io) 4947c478bd9Sstevel@tonic-gate { 4957c478bd9Sstevel@tonic-gate ASSERT(io->io_next == NULL); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate io->io_next = iob->iob_iop; 4987c478bd9Sstevel@tonic-gate iob->iob_iop = mdb_io_hold(io); 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate mdb_io_t * 5027c478bd9Sstevel@tonic-gate mdb_iob_pop_io(mdb_iob_t *iob) 5037c478bd9Sstevel@tonic-gate { 5047c478bd9Sstevel@tonic-gate mdb_io_t *io = iob->iob_iop; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (io != NULL) { 5077c478bd9Sstevel@tonic-gate iob->iob_iop = io->io_next; 5087c478bd9Sstevel@tonic-gate io->io_next = NULL; 5097c478bd9Sstevel@tonic-gate mdb_io_rele(io); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate return (io); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate void 5167c478bd9Sstevel@tonic-gate mdb_iob_resize(mdb_iob_t *iob, size_t rows, size_t cols) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate if (cols > iob->iob_bufsiz) 5197c478bd9Sstevel@tonic-gate iob->iob_cols = iob->iob_bufsiz; 5207c478bd9Sstevel@tonic-gate else 5217c478bd9Sstevel@tonic-gate iob->iob_cols = cols != 0 ? cols : MDB_IOB_DEFCOLS; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate iob->iob_rows = rows != 0 ? rows : MDB_IOB_DEFROWS; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate void 5277c478bd9Sstevel@tonic-gate mdb_iob_setpager(mdb_iob_t *iob, mdb_io_t *pgio) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate struct winsize winsz; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if (iob->iob_pgp != NULL) { 5327c478bd9Sstevel@tonic-gate IOP_UNLINK(iob->iob_pgp, iob); 5337c478bd9Sstevel@tonic-gate mdb_io_rele(iob->iob_pgp); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate iob->iob_flags |= MDB_IOB_PGENABLE; 5377c478bd9Sstevel@tonic-gate iob->iob_flags &= ~(MDB_IOB_PGSINGLE | MDB_IOB_PGCONT); 5387c478bd9Sstevel@tonic-gate iob->iob_pgp = mdb_io_hold(pgio); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate IOP_LINK(iob->iob_pgp, iob); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate if (IOP_CTL(pgio, TIOCGWINSZ, &winsz) == 0) 5437c478bd9Sstevel@tonic-gate mdb_iob_resize(iob, (size_t)winsz.ws_row, (size_t)winsz.ws_col); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate void 5477c478bd9Sstevel@tonic-gate mdb_iob_tabstop(mdb_iob_t *iob, size_t tabstop) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate iob->iob_tabstop = MIN(tabstop, iob->iob_cols - 1); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate void 5537c478bd9Sstevel@tonic-gate mdb_iob_margin(mdb_iob_t *iob, size_t margin) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate iob_unindent(iob); 5567c478bd9Sstevel@tonic-gate iob->iob_margin = MIN(margin, iob->iob_cols - 1); 5577c478bd9Sstevel@tonic-gate iob_indent(iob); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate void 5617c478bd9Sstevel@tonic-gate mdb_iob_setbuf(mdb_iob_t *iob, void *buf, size_t bufsiz) 5627c478bd9Sstevel@tonic-gate { 5637c478bd9Sstevel@tonic-gate ASSERT(buf != NULL && bufsiz != 0); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate mdb_free(iob->iob_buf, iob->iob_bufsiz); 5667c478bd9Sstevel@tonic-gate iob->iob_buf = buf; 5677c478bd9Sstevel@tonic-gate iob->iob_bufsiz = bufsiz; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_WRONLY) 5707c478bd9Sstevel@tonic-gate iob->iob_cols = MIN(iob->iob_cols, iob->iob_bufsiz); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate void 5747c478bd9Sstevel@tonic-gate mdb_iob_clearlines(mdb_iob_t *iob) 5757c478bd9Sstevel@tonic-gate { 5767c478bd9Sstevel@tonic-gate iob->iob_flags &= ~(MDB_IOB_PGSINGLE | MDB_IOB_PGCONT); 5777c478bd9Sstevel@tonic-gate iob->iob_nlines = 0; 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate void 5817c478bd9Sstevel@tonic-gate mdb_iob_setflags(mdb_iob_t *iob, uint_t flags) 5827c478bd9Sstevel@tonic-gate { 5837c478bd9Sstevel@tonic-gate iob->iob_flags |= flags; 5847c478bd9Sstevel@tonic-gate if (flags & MDB_IOB_INDENT) 5857c478bd9Sstevel@tonic-gate iob_indent(iob); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate void 5897c478bd9Sstevel@tonic-gate mdb_iob_clrflags(mdb_iob_t *iob, uint_t flags) 5907c478bd9Sstevel@tonic-gate { 5917c478bd9Sstevel@tonic-gate iob->iob_flags &= ~flags; 5927c478bd9Sstevel@tonic-gate if (flags & MDB_IOB_INDENT) 5937c478bd9Sstevel@tonic-gate iob_unindent(iob); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate uint_t 5977c478bd9Sstevel@tonic-gate mdb_iob_getflags(mdb_iob_t *iob) 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate return (iob->iob_flags); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate static uintmax_t 6037c478bd9Sstevel@tonic-gate vec_arg(const mdb_arg_t **app) 6047c478bd9Sstevel@tonic-gate { 6057c478bd9Sstevel@tonic-gate uintmax_t value; 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate if ((*app)->a_type == MDB_TYPE_STRING) 6087c478bd9Sstevel@tonic-gate value = (uintmax_t)(uintptr_t)(*app)->a_un.a_str; 6097c478bd9Sstevel@tonic-gate else 6107c478bd9Sstevel@tonic-gate value = (*app)->a_un.a_val; 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate (*app)++; 6137c478bd9Sstevel@tonic-gate return (value); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate static const char * 6177c478bd9Sstevel@tonic-gate iob_size2str(intsize_t size) 6187c478bd9Sstevel@tonic-gate { 6197c478bd9Sstevel@tonic-gate switch (size) { 6207c478bd9Sstevel@tonic-gate case SZ_SHORT: 6217c478bd9Sstevel@tonic-gate return ("short"); 6227c478bd9Sstevel@tonic-gate case SZ_INT: 6237c478bd9Sstevel@tonic-gate return ("int"); 6247c478bd9Sstevel@tonic-gate case SZ_LONG: 6257c478bd9Sstevel@tonic-gate return ("long"); 6267c478bd9Sstevel@tonic-gate case SZ_LONGLONG: 6277c478bd9Sstevel@tonic-gate return ("long long"); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate return (""); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * In order to simplify maintenance of the ::formats display, we provide an 6347c478bd9Sstevel@tonic-gate * unparser for mdb_printf format strings that converts a simple format 6357c478bd9Sstevel@tonic-gate * string with one specifier into a descriptive representation, e.g. 6367c478bd9Sstevel@tonic-gate * mdb_iob_format2str("%llx") returns "hexadecimal long long". 6377c478bd9Sstevel@tonic-gate */ 6387c478bd9Sstevel@tonic-gate const char * 6397c478bd9Sstevel@tonic-gate mdb_iob_format2str(const char *format) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate intsize_t size = SZ_INT; 6427c478bd9Sstevel@tonic-gate const char *p; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate static char buf[64]; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate buf[0] = '\0'; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if ((p = strchr(format, '%')) == NULL) 6497c478bd9Sstevel@tonic-gate goto done; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate fmt_switch: 6527c478bd9Sstevel@tonic-gate switch (*++p) { 6537c478bd9Sstevel@tonic-gate case '0': case '1': case '2': case '3': case '4': 6547c478bd9Sstevel@tonic-gate case '5': case '6': case '7': case '8': case '9': 6557c478bd9Sstevel@tonic-gate while (*p >= '0' && *p <= '9') 6567c478bd9Sstevel@tonic-gate p++; 6577c478bd9Sstevel@tonic-gate p--; 6587c478bd9Sstevel@tonic-gate goto fmt_switch; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate case 'a': 6617c478bd9Sstevel@tonic-gate case 'A': 6627c478bd9Sstevel@tonic-gate return ("symbol"); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate case 'b': 6657c478bd9Sstevel@tonic-gate (void) strcpy(buf, "unsigned "); 6667c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 6677c478bd9Sstevel@tonic-gate (void) strcat(buf, " bitfield"); 6687c478bd9Sstevel@tonic-gate break; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate case 'c': 6717c478bd9Sstevel@tonic-gate return ("character"); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate case 'd': 6747c478bd9Sstevel@tonic-gate case 'i': 6757c478bd9Sstevel@tonic-gate (void) strcpy(buf, "decimal signed "); 6767c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 6777c478bd9Sstevel@tonic-gate break; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate case 'e': 6807c478bd9Sstevel@tonic-gate case 'E': 6817c478bd9Sstevel@tonic-gate case 'g': 6827c478bd9Sstevel@tonic-gate case 'G': 6837c478bd9Sstevel@tonic-gate return ("double"); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate case 'h': 6867c478bd9Sstevel@tonic-gate size = SZ_SHORT; 6877c478bd9Sstevel@tonic-gate goto fmt_switch; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate case 'I': 6907c478bd9Sstevel@tonic-gate return ("IPv4 address"); 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate case 'l': 6937c478bd9Sstevel@tonic-gate if (size >= SZ_LONG) 6947c478bd9Sstevel@tonic-gate size = SZ_LONGLONG; 6957c478bd9Sstevel@tonic-gate else 6967c478bd9Sstevel@tonic-gate size = SZ_LONG; 6977c478bd9Sstevel@tonic-gate goto fmt_switch; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate case 'm': 7007c478bd9Sstevel@tonic-gate return ("margin"); 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate case 'N': 7037c478bd9Sstevel@tonic-gate return ("IPv6 address"); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate case 'o': 7067c478bd9Sstevel@tonic-gate (void) strcpy(buf, "octal unsigned "); 7077c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 7087c478bd9Sstevel@tonic-gate break; 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate case 'p': 7117c478bd9Sstevel@tonic-gate return ("pointer"); 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate case 'q': 7147c478bd9Sstevel@tonic-gate (void) strcpy(buf, "octal signed "); 7157c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 7167c478bd9Sstevel@tonic-gate break; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate case 'r': 7197c478bd9Sstevel@tonic-gate (void) strcpy(buf, "default radix unsigned "); 7207c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 7217c478bd9Sstevel@tonic-gate break; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate case 'R': 7247c478bd9Sstevel@tonic-gate (void) strcpy(buf, "default radix signed "); 7257c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 7267c478bd9Sstevel@tonic-gate break; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate case 's': 7297c478bd9Sstevel@tonic-gate return ("string"); 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate case 't': 7327c478bd9Sstevel@tonic-gate case 'T': 7337c478bd9Sstevel@tonic-gate return ("tab"); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate case 'u': 7367c478bd9Sstevel@tonic-gate (void) strcpy(buf, "decimal unsigned "); 7377c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 7387c478bd9Sstevel@tonic-gate break; 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate case 'x': 7417c478bd9Sstevel@tonic-gate case 'X': 7427c478bd9Sstevel@tonic-gate (void) strcat(buf, "hexadecimal "); 7437c478bd9Sstevel@tonic-gate (void) strcat(buf, iob_size2str(size)); 7447c478bd9Sstevel@tonic-gate break; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate case 'Y': 7477c478bd9Sstevel@tonic-gate return ("time_t"); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate case '<': 7507c478bd9Sstevel@tonic-gate return ("terminal attribute"); 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate case '?': 7537c478bd9Sstevel@tonic-gate case '#': 7547c478bd9Sstevel@tonic-gate case '+': 7557c478bd9Sstevel@tonic-gate case '-': 7567c478bd9Sstevel@tonic-gate goto fmt_switch; 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate done: 7607c478bd9Sstevel@tonic-gate if (buf[0] == '\0') 7617c478bd9Sstevel@tonic-gate (void) strcpy(buf, "text"); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate return ((const char *)buf); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate static const char * 7677c478bd9Sstevel@tonic-gate iob_int2str(varglist_t *ap, intsize_t size, int base, uint_t flags, int *zero, 7687c478bd9Sstevel@tonic-gate u_longlong_t *value) 7697c478bd9Sstevel@tonic-gate { 7707c478bd9Sstevel@tonic-gate uintmax_t i; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate switch (size) { 7737c478bd9Sstevel@tonic-gate case SZ_LONGLONG: 7747c478bd9Sstevel@tonic-gate if (flags & NTOS_UNSIGNED) 7757c478bd9Sstevel@tonic-gate i = (u_longlong_t)VA_ARG(ap, u_longlong_t); 7767c478bd9Sstevel@tonic-gate else 7777c478bd9Sstevel@tonic-gate i = (longlong_t)VA_ARG(ap, longlong_t); 7787c478bd9Sstevel@tonic-gate break; 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate case SZ_LONG: 7817c478bd9Sstevel@tonic-gate if (flags & NTOS_UNSIGNED) 7827c478bd9Sstevel@tonic-gate i = (ulong_t)VA_ARG(ap, ulong_t); 7837c478bd9Sstevel@tonic-gate else 7847c478bd9Sstevel@tonic-gate i = (long)VA_ARG(ap, long); 7857c478bd9Sstevel@tonic-gate break; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate case SZ_SHORT: 7887c478bd9Sstevel@tonic-gate if (flags & NTOS_UNSIGNED) 7897c478bd9Sstevel@tonic-gate i = (ushort_t)VA_ARG(ap, uint_t); 7907c478bd9Sstevel@tonic-gate else 7917c478bd9Sstevel@tonic-gate i = (short)VA_ARG(ap, int); 7927c478bd9Sstevel@tonic-gate break; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate default: 7957c478bd9Sstevel@tonic-gate if (flags & NTOS_UNSIGNED) 7967c478bd9Sstevel@tonic-gate i = (uint_t)VA_ARG(ap, uint_t); 7977c478bd9Sstevel@tonic-gate else 7987c478bd9Sstevel@tonic-gate i = (int)VA_ARG(ap, int); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate *zero = i == 0; /* Return flag indicating if result was zero */ 8027c478bd9Sstevel@tonic-gate *value = i; /* Return value retrieved from va_list */ 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate return (numtostr(i, base, flags)); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate static const char * 8087c478bd9Sstevel@tonic-gate iob_time2str(time_t *tmp) 8097c478bd9Sstevel@tonic-gate { 8107c478bd9Sstevel@tonic-gate /* 8117c478bd9Sstevel@tonic-gate * ctime(3c) returns a string of the form 8127c478bd9Sstevel@tonic-gate * "Fri Sep 13 00:00:00 1986\n\0". We turn this into the canonical 8137c478bd9Sstevel@tonic-gate * adb /y format "1986 Sep 13 00:00:00" below. 8147c478bd9Sstevel@tonic-gate */ 8157c478bd9Sstevel@tonic-gate const char *src = ctime(tmp); 8167c478bd9Sstevel@tonic-gate static char buf[32]; 8177c478bd9Sstevel@tonic-gate char *dst = buf; 8187c478bd9Sstevel@tonic-gate int i; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate if (src == NULL) 821*a727d47aSjwadams return (numtostr((uintmax_t)*tmp, mdb.m_radix, 0)); 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate for (i = 20; i < 24; i++) 8247c478bd9Sstevel@tonic-gate *dst++ = src[i]; /* Copy the 4-digit year */ 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate for (i = 3; i < 19; i++) 8277c478bd9Sstevel@tonic-gate *dst++ = src[i]; /* Copy month, day, and h:m:s */ 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate *dst = '\0'; 8307c478bd9Sstevel@tonic-gate return (buf); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate static const char * 8347c478bd9Sstevel@tonic-gate iob_addr2str(uintptr_t addr) 8357c478bd9Sstevel@tonic-gate { 8367c478bd9Sstevel@tonic-gate static char buf[MDB_TGT_SYM_NAMLEN]; 8377c478bd9Sstevel@tonic-gate char *name = buf; 8387c478bd9Sstevel@tonic-gate longlong_t offset; 8397c478bd9Sstevel@tonic-gate GElf_Sym sym; 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_addr(mdb.m_target, addr, 8427c478bd9Sstevel@tonic-gate MDB_TGT_SYM_FUZZY, buf, sizeof (buf), &sym, NULL) == -1) 8437c478bd9Sstevel@tonic-gate return (NULL); 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate if (mdb.m_demangler != NULL && (mdb.m_flags & MDB_FL_DEMANGLE)) 8467c478bd9Sstevel@tonic-gate name = (char *)mdb_dem_convert(mdb.m_demangler, buf); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* 8497c478bd9Sstevel@tonic-gate * Here we provide a little cooperation between the %a formatting code 8507c478bd9Sstevel@tonic-gate * and the proc target: if the initial address passed to %a is in fact 8517c478bd9Sstevel@tonic-gate * a PLT address, the proc target's lookup_by_addr code will convert 8527c478bd9Sstevel@tonic-gate * this to the PLT destination (a different address). We do not want 8537c478bd9Sstevel@tonic-gate * to append a "+/-offset" suffix based on comparison with the query 8547c478bd9Sstevel@tonic-gate * symbol in this case because the proc target has really done a hidden 8557c478bd9Sstevel@tonic-gate * query for us with a different address. We detect this case by 8567c478bd9Sstevel@tonic-gate * comparing the initial characters of buf to the special PLT= string. 8577c478bd9Sstevel@tonic-gate */ 8587c478bd9Sstevel@tonic-gate if (sym.st_value != addr && strncmp(name, "PLT=", 4) != 0) { 8597c478bd9Sstevel@tonic-gate if (sym.st_value > addr) 8607c478bd9Sstevel@tonic-gate offset = -(longlong_t)(sym.st_value - addr); 8617c478bd9Sstevel@tonic-gate else 8627c478bd9Sstevel@tonic-gate offset = (longlong_t)(addr - sym.st_value); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate (void) strcat(name, numtostr(offset, mdb.m_radix, 8657c478bd9Sstevel@tonic-gate NTOS_SIGNPOS | NTOS_SHOWBASE)); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate return (name); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate static int 8727c478bd9Sstevel@tonic-gate iob_setattr(mdb_iob_t *iob, const char *s, size_t nbytes) 8737c478bd9Sstevel@tonic-gate { 8747c478bd9Sstevel@tonic-gate uint_t attr; 8757c478bd9Sstevel@tonic-gate int req; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate if (iob->iob_pgp == NULL) 8787c478bd9Sstevel@tonic-gate return (set_errno(ENOTTY)); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate if (nbytes != 0 && *s == '/') { 8817c478bd9Sstevel@tonic-gate req = ATT_OFF; 8827c478bd9Sstevel@tonic-gate nbytes--; 8837c478bd9Sstevel@tonic-gate s++; 8847c478bd9Sstevel@tonic-gate } else 8857c478bd9Sstevel@tonic-gate req = ATT_ON; 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate if (nbytes != 1) 8887c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate switch (*s) { 8917c478bd9Sstevel@tonic-gate case 's': 8927c478bd9Sstevel@tonic-gate attr = ATT_STANDOUT; 8937c478bd9Sstevel@tonic-gate break; 8947c478bd9Sstevel@tonic-gate case 'u': 8957c478bd9Sstevel@tonic-gate attr = ATT_UNDERLINE; 8967c478bd9Sstevel@tonic-gate break; 8977c478bd9Sstevel@tonic-gate case 'r': 8987c478bd9Sstevel@tonic-gate attr = ATT_REVERSE; 8997c478bd9Sstevel@tonic-gate break; 9007c478bd9Sstevel@tonic-gate case 'b': 9017c478bd9Sstevel@tonic-gate attr = ATT_BOLD; 9027c478bd9Sstevel@tonic-gate break; 9037c478bd9Sstevel@tonic-gate case 'd': 9047c478bd9Sstevel@tonic-gate attr = ATT_DIM; 9057c478bd9Sstevel@tonic-gate break; 9067c478bd9Sstevel@tonic-gate case 'a': 9077c478bd9Sstevel@tonic-gate attr = ATT_ALTCHARSET; 9087c478bd9Sstevel@tonic-gate break; 9097c478bd9Sstevel@tonic-gate default: 9107c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* 9147c478bd9Sstevel@tonic-gate * We need to flush the current buffer contents before calling 9157c478bd9Sstevel@tonic-gate * IOP_SETATTR because IOP_SETATTR may need to synchronously output 9167c478bd9Sstevel@tonic-gate * terminal escape sequences directly to the underlying device. 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate (void) iob_write(iob, iob->iob_iop, iob->iob_buf, iob->iob_nbytes); 9197c478bd9Sstevel@tonic-gate iob->iob_bufp = &iob->iob_buf[0]; 9207c478bd9Sstevel@tonic-gate iob->iob_nbytes = 0; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate return (IOP_SETATTR(iob->iob_pgp, req, attr)); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate static void 9267c478bd9Sstevel@tonic-gate iob_bits2str(mdb_iob_t *iob, u_longlong_t value, const mdb_bitmask_t *bmp, 9277c478bd9Sstevel@tonic-gate mdb_bool_t altflag) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate mdb_bool_t delim = FALSE; 9307c478bd9Sstevel@tonic-gate const char *str; 9317c478bd9Sstevel@tonic-gate size_t width; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate if (bmp == NULL) 9347c478bd9Sstevel@tonic-gate goto out; 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate for (; bmp->bm_name != NULL; bmp++) { 9377c478bd9Sstevel@tonic-gate if ((value & bmp->bm_mask) == bmp->bm_bits) { 9387c478bd9Sstevel@tonic-gate width = strlen(bmp->bm_name) + delim; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate if (IOB_WRAPNOW(iob, width)) 9417c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate if (delim) 9447c478bd9Sstevel@tonic-gate mdb_iob_putc(iob, ','); 9457c478bd9Sstevel@tonic-gate else 9467c478bd9Sstevel@tonic-gate delim = TRUE; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate mdb_iob_puts(iob, bmp->bm_name); 9497c478bd9Sstevel@tonic-gate value &= ~bmp->bm_bits; 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate out: 9547c478bd9Sstevel@tonic-gate if (altflag == TRUE && (delim == FALSE || value != 0)) { 9557c478bd9Sstevel@tonic-gate str = numtostr(value, 16, NTOS_UNSIGNED | NTOS_SHOWBASE); 9567c478bd9Sstevel@tonic-gate width = strlen(str) + delim; 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (IOB_WRAPNOW(iob, width)) 9597c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 9607c478bd9Sstevel@tonic-gate if (delim) 9617c478bd9Sstevel@tonic-gate mdb_iob_putc(iob, ','); 9627c478bd9Sstevel@tonic-gate mdb_iob_puts(iob, str); 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate static const char * 9677c478bd9Sstevel@tonic-gate iob_inaddr2str(uint32_t addr) 9687c478bd9Sstevel@tonic-gate { 9697c478bd9Sstevel@tonic-gate static char buf[INET_ADDRSTRLEN]; 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate (void) mdb_inet_ntop(AF_INET, &addr, buf, sizeof (buf)); 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate return (buf); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate static const char * 9777c478bd9Sstevel@tonic-gate iob_ipv6addr2str(void *addr) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate static char buf[INET6_ADDRSTRLEN]; 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate (void) mdb_inet_ntop(AF_INET6, addr, buf, sizeof (buf)); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate return (buf); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate static const char * 9877c478bd9Sstevel@tonic-gate iob_getvar(const char *s, size_t len) 9887c478bd9Sstevel@tonic-gate { 9897c478bd9Sstevel@tonic-gate mdb_var_t *val; 9907c478bd9Sstevel@tonic-gate char *var; 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate if (len == 0) { 9937c478bd9Sstevel@tonic-gate (void) set_errno(EINVAL); 9947c478bd9Sstevel@tonic-gate return (NULL); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate var = strndup(s, len); 9987c478bd9Sstevel@tonic-gate val = mdb_nv_lookup(&mdb.m_nv, var); 9997c478bd9Sstevel@tonic-gate strfree(var); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate if (val == NULL) { 10027c478bd9Sstevel@tonic-gate (void) set_errno(EINVAL); 10037c478bd9Sstevel@tonic-gate return (NULL); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate return (numtostr(mdb_nv_get_value(val), 10, 0)); 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate /* 10107c478bd9Sstevel@tonic-gate * The iob_doprnt function forms the main engine of the debugger's output 10117c478bd9Sstevel@tonic-gate * formatting capabilities. Note that this is NOT exactly compatible with 10127c478bd9Sstevel@tonic-gate * the printf(3S) family, nor is it intended to be so. We support some 10137c478bd9Sstevel@tonic-gate * extensions and format characters not supported by printf(3S), and we 10147c478bd9Sstevel@tonic-gate * explicitly do NOT provide support for %C, %S, %ws (wide-character strings), 10157c478bd9Sstevel@tonic-gate * do NOT provide for the complete functionality of %f, %e, %E, %g, %G 10167c478bd9Sstevel@tonic-gate * (alternate double formats), and do NOT support %.x (precision specification). 10177c478bd9Sstevel@tonic-gate * Note that iob_doprnt consumes varargs off the original va_list. 10187c478bd9Sstevel@tonic-gate */ 10197c478bd9Sstevel@tonic-gate static void 10207c478bd9Sstevel@tonic-gate iob_doprnt(mdb_iob_t *iob, const char *format, varglist_t *ap) 10217c478bd9Sstevel@tonic-gate { 10227c478bd9Sstevel@tonic-gate char c[2] = { 0, 0 }; /* Buffer for single character output */ 10237c478bd9Sstevel@tonic-gate const char *p; /* Current position in format string */ 10247c478bd9Sstevel@tonic-gate size_t len; /* Length of format string to copy verbatim */ 10257c478bd9Sstevel@tonic-gate size_t altlen; /* Length of alternate print format prefix */ 10267c478bd9Sstevel@tonic-gate const char *altstr; /* Alternate print format prefix */ 10277c478bd9Sstevel@tonic-gate const char *symstr; /* Symbol + offset string */ 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate u_longlong_t val; /* Current integer value */ 10307c478bd9Sstevel@tonic-gate intsize_t size; /* Current integer value size */ 10317c478bd9Sstevel@tonic-gate uint_t flags; /* Current flags to pass to iob_int2str */ 10327c478bd9Sstevel@tonic-gate size_t width; /* Current field width */ 10337c478bd9Sstevel@tonic-gate int zero; /* If != 0, then integer value == 0 */ 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate mdb_bool_t f_alt; /* Use alternate print format (%#) */ 10367c478bd9Sstevel@tonic-gate mdb_bool_t f_altsuff; /* Alternate print format is a suffix */ 10377c478bd9Sstevel@tonic-gate mdb_bool_t f_zfill; /* Zero-fill field (%0) */ 10387c478bd9Sstevel@tonic-gate mdb_bool_t f_left; /* Left-adjust field (%-) */ 10397c478bd9Sstevel@tonic-gate mdb_bool_t f_digits; /* Explicit digits used to set field width */ 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate union { 10427c478bd9Sstevel@tonic-gate const char *str; 10437c478bd9Sstevel@tonic-gate uint32_t ui32; 10447c478bd9Sstevel@tonic-gate void *ptr; 10457c478bd9Sstevel@tonic-gate time_t tm; 10467c478bd9Sstevel@tonic-gate char c; 10477c478bd9Sstevel@tonic-gate double d; 10487c478bd9Sstevel@tonic-gate long double ld; 10497c478bd9Sstevel@tonic-gate } u; 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate while ((p = strchr(format, '%')) != NULL) { 10547c478bd9Sstevel@tonic-gate /* 10557c478bd9Sstevel@tonic-gate * Output the format string verbatim up to the next '%' char 10567c478bd9Sstevel@tonic-gate */ 10577c478bd9Sstevel@tonic-gate if (p != format) { 10587c478bd9Sstevel@tonic-gate len = p - format; 10597c478bd9Sstevel@tonic-gate if (IOB_WRAPNOW(iob, len) && *format != '\n') 10607c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 10617c478bd9Sstevel@tonic-gate mdb_iob_nputs(iob, format, len); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate /* 10657c478bd9Sstevel@tonic-gate * Now we need to parse the sequence of format characters 10667c478bd9Sstevel@tonic-gate * following the % marker and do the appropriate thing. 10677c478bd9Sstevel@tonic-gate */ 10687c478bd9Sstevel@tonic-gate size = SZ_INT; /* Use normal-sized int by default */ 10697c478bd9Sstevel@tonic-gate flags = 0; /* Clear numtostr() format flags */ 10707c478bd9Sstevel@tonic-gate width = 0; /* No field width limit by default */ 10717c478bd9Sstevel@tonic-gate altlen = 0; /* No alternate format string yet */ 10727c478bd9Sstevel@tonic-gate altstr = NULL; /* No alternate format string yet */ 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate f_alt = FALSE; /* Alternate format off by default */ 10757c478bd9Sstevel@tonic-gate f_altsuff = FALSE; /* Alternate format is a prefix */ 10767c478bd9Sstevel@tonic-gate f_zfill = FALSE; /* Zero-fill off by default */ 10777c478bd9Sstevel@tonic-gate f_left = FALSE; /* Left-adjust off by default */ 10787c478bd9Sstevel@tonic-gate f_digits = FALSE; /* No digits for width specified yet */ 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate fmt_switch: 10817c478bd9Sstevel@tonic-gate switch (*++p) { 10827c478bd9Sstevel@tonic-gate case '0': case '1': case '2': case '3': case '4': 10837c478bd9Sstevel@tonic-gate case '5': case '6': case '7': case '8': case '9': 10847c478bd9Sstevel@tonic-gate if (f_digits == FALSE && *p == '0') { 10857c478bd9Sstevel@tonic-gate f_zfill = TRUE; 10867c478bd9Sstevel@tonic-gate goto fmt_switch; 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate if (f_digits == FALSE) 10907c478bd9Sstevel@tonic-gate width = 0; /* clear any other width specifier */ 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate for (u.c = *p; u.c >= '0' && u.c <= '9'; u.c = *++p) 10937c478bd9Sstevel@tonic-gate width = width * 10 + u.c - '0'; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate p--; 10967c478bd9Sstevel@tonic-gate f_digits = TRUE; 10977c478bd9Sstevel@tonic-gate goto fmt_switch; 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate case 'a': 11007c478bd9Sstevel@tonic-gate if (size < SZ_LONG) 11017c478bd9Sstevel@tonic-gate size = SZ_LONG; /* Bump to size of uintptr_t */ 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 16, 11047c478bd9Sstevel@tonic-gate NTOS_UNSIGNED | NTOS_SHOWBASE, &zero, &val); 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate if ((symstr = iob_addr2str(val)) != NULL) 11077c478bd9Sstevel@tonic-gate u.str = symstr; 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate if (f_alt == TRUE) { 11107c478bd9Sstevel@tonic-gate f_altsuff = TRUE; 11117c478bd9Sstevel@tonic-gate altstr = ":"; 11127c478bd9Sstevel@tonic-gate altlen = 1; 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate break; 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate case 'A': 11177c478bd9Sstevel@tonic-gate if (size < SZ_LONG) 11187c478bd9Sstevel@tonic-gate size = SZ_LONG; /* Bump to size of uintptr_t */ 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate (void) iob_int2str(ap, size, 16, 11217c478bd9Sstevel@tonic-gate NTOS_UNSIGNED, &zero, &val); 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate u.str = iob_addr2str(val); 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate if (f_alt == TRUE && u.str == NULL) 11267c478bd9Sstevel@tonic-gate u.str = "?"; 11277c478bd9Sstevel@tonic-gate break; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate case 'b': 11307c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 16, 11317c478bd9Sstevel@tonic-gate NTOS_UNSIGNED | NTOS_SHOWBASE, &zero, &val); 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate iob_bits2str(iob, val, VA_PTRARG(ap), f_alt); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate format = ++p; 11367c478bd9Sstevel@tonic-gate continue; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate case 'c': 11397c478bd9Sstevel@tonic-gate c[0] = (char)VA_ARG(ap, int); 11407c478bd9Sstevel@tonic-gate u.str = c; 11417c478bd9Sstevel@tonic-gate break; 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate case 'd': 11447c478bd9Sstevel@tonic-gate case 'i': 11457c478bd9Sstevel@tonic-gate if (f_alt) 11467c478bd9Sstevel@tonic-gate flags |= NTOS_SHOWBASE; 11477c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 10, flags, &zero, &val); 11487c478bd9Sstevel@tonic-gate break; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate /* No floating point in kmdb */ 11517c478bd9Sstevel@tonic-gate #ifndef _KMDB 11527c478bd9Sstevel@tonic-gate case 'e': 11537c478bd9Sstevel@tonic-gate case 'E': 11547c478bd9Sstevel@tonic-gate u.d = VA_ARG(ap, double); 11557c478bd9Sstevel@tonic-gate u.str = doubletos(u.d, 7, *p); 11567c478bd9Sstevel@tonic-gate break; 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate case 'g': 11597c478bd9Sstevel@tonic-gate case 'G': 11607c478bd9Sstevel@tonic-gate if (size >= SZ_LONG) { 11617c478bd9Sstevel@tonic-gate u.ld = VA_ARG(ap, long double); 11627c478bd9Sstevel@tonic-gate u.str = longdoubletos(&u.ld, 16, 11637c478bd9Sstevel@tonic-gate (*p == 'g') ? 'e' : 'E'); 11647c478bd9Sstevel@tonic-gate } else { 11657c478bd9Sstevel@tonic-gate u.d = VA_ARG(ap, double); 11667c478bd9Sstevel@tonic-gate u.str = doubletos(u.d, 16, 11677c478bd9Sstevel@tonic-gate (*p == 'g') ? 'e' : 'E'); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate break; 11707c478bd9Sstevel@tonic-gate #endif 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate case 'h': 11737c478bd9Sstevel@tonic-gate size = SZ_SHORT; 11747c478bd9Sstevel@tonic-gate goto fmt_switch; 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate case 'I': 11777c478bd9Sstevel@tonic-gate u.ui32 = VA_ARG(ap, uint32_t); 11787c478bd9Sstevel@tonic-gate u.str = iob_inaddr2str(u.ui32); 11797c478bd9Sstevel@tonic-gate break; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate case 'l': 11827c478bd9Sstevel@tonic-gate if (size >= SZ_LONG) 11837c478bd9Sstevel@tonic-gate size = SZ_LONGLONG; 11847c478bd9Sstevel@tonic-gate else 11857c478bd9Sstevel@tonic-gate size = SZ_LONG; 11867c478bd9Sstevel@tonic-gate goto fmt_switch; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate case 'm': 11897c478bd9Sstevel@tonic-gate if (iob->iob_nbytes == 0) { 11907c478bd9Sstevel@tonic-gate mdb_iob_ws(iob, (width != 0) ? width : 11917c478bd9Sstevel@tonic-gate iob->iob_margin); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate format = ++p; 11947c478bd9Sstevel@tonic-gate continue; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate case 'N': 11977c478bd9Sstevel@tonic-gate u.ptr = VA_PTRARG(ap); 11987c478bd9Sstevel@tonic-gate u.str = iob_ipv6addr2str(u.ptr); 11997c478bd9Sstevel@tonic-gate break; 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate case 'o': 12027c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 8, NTOS_UNSIGNED, 12037c478bd9Sstevel@tonic-gate &zero, &val); 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate if (f_alt && !zero) { 12067c478bd9Sstevel@tonic-gate altstr = "0"; 12077c478bd9Sstevel@tonic-gate altlen = 1; 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate break; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate case 'p': 12127c478bd9Sstevel@tonic-gate u.ptr = VA_PTRARG(ap); 12137c478bd9Sstevel@tonic-gate u.str = numtostr((uintptr_t)u.ptr, 16, NTOS_UNSIGNED); 12147c478bd9Sstevel@tonic-gate break; 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate case 'q': 12177c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 8, flags, &zero, &val); 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate if (f_alt && !zero) { 12207c478bd9Sstevel@tonic-gate altstr = "0"; 12217c478bd9Sstevel@tonic-gate altlen = 1; 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate break; 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate case 'r': 12267c478bd9Sstevel@tonic-gate if (f_alt) 12277c478bd9Sstevel@tonic-gate flags |= NTOS_SHOWBASE; 12287c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, mdb.m_radix, 12297c478bd9Sstevel@tonic-gate NTOS_UNSIGNED | flags, &zero, &val); 12307c478bd9Sstevel@tonic-gate break; 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate case 'R': 12337c478bd9Sstevel@tonic-gate if (f_alt) 12347c478bd9Sstevel@tonic-gate flags |= NTOS_SHOWBASE; 12357c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, mdb.m_radix, flags, 12367c478bd9Sstevel@tonic-gate &zero, &val); 12377c478bd9Sstevel@tonic-gate break; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate case 's': 12407c478bd9Sstevel@tonic-gate u.str = VA_PTRARG(ap); 12417c478bd9Sstevel@tonic-gate if (u.str == NULL) 12427c478bd9Sstevel@tonic-gate u.str = "<NULL>"; /* Be forgiving of NULL */ 12437c478bd9Sstevel@tonic-gate break; 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate case 't': 12467c478bd9Sstevel@tonic-gate if (width != 0) { 12477c478bd9Sstevel@tonic-gate while (width-- > 0) 12487c478bd9Sstevel@tonic-gate mdb_iob_tab(iob); 12497c478bd9Sstevel@tonic-gate } else 12507c478bd9Sstevel@tonic-gate mdb_iob_tab(iob); 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate format = ++p; 12537c478bd9Sstevel@tonic-gate continue; 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate case 'T': 12567c478bd9Sstevel@tonic-gate if (width != 0 && (iob->iob_nbytes % width) != 0) { 12577c478bd9Sstevel@tonic-gate size_t ots = iob->iob_tabstop; 12587c478bd9Sstevel@tonic-gate iob->iob_tabstop = width; 12597c478bd9Sstevel@tonic-gate mdb_iob_tab(iob); 12607c478bd9Sstevel@tonic-gate iob->iob_tabstop = ots; 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate format = ++p; 12637c478bd9Sstevel@tonic-gate continue; 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate case 'u': 12667c478bd9Sstevel@tonic-gate if (f_alt) 12677c478bd9Sstevel@tonic-gate flags |= NTOS_SHOWBASE; 12687c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 10, 12697c478bd9Sstevel@tonic-gate flags | NTOS_UNSIGNED, &zero, &val); 12707c478bd9Sstevel@tonic-gate break; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate case 'x': 12737c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 16, NTOS_UNSIGNED, 12747c478bd9Sstevel@tonic-gate &zero, &val); 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate if (f_alt && !zero) { 12777c478bd9Sstevel@tonic-gate altstr = "0x"; 12787c478bd9Sstevel@tonic-gate altlen = 2; 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate break; 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate case 'X': 12837c478bd9Sstevel@tonic-gate u.str = iob_int2str(ap, size, 16, 12847c478bd9Sstevel@tonic-gate NTOS_UNSIGNED | NTOS_UPCASE, &zero, &val); 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate if (f_alt && !zero) { 12877c478bd9Sstevel@tonic-gate altstr = "0X"; 12887c478bd9Sstevel@tonic-gate altlen = 2; 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate break; 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate case 'Y': 12937c478bd9Sstevel@tonic-gate u.tm = VA_ARG(ap, time_t); 12947c478bd9Sstevel@tonic-gate u.str = iob_time2str(&u.tm); 12957c478bd9Sstevel@tonic-gate break; 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate case '<': 12987c478bd9Sstevel@tonic-gate /* 12997c478bd9Sstevel@tonic-gate * Used to turn attributes on (<b>), to turn them 13007c478bd9Sstevel@tonic-gate * off (</b>), or to print variables (<_var>). 13017c478bd9Sstevel@tonic-gate */ 13027c478bd9Sstevel@tonic-gate for (u.str = ++p; *p != '\0' && *p != '>'; p++) 13037c478bd9Sstevel@tonic-gate continue; 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate if (*p == '>') { 13067c478bd9Sstevel@tonic-gate size_t paramlen = p - u.str; 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate if (paramlen > 0) { 13097c478bd9Sstevel@tonic-gate if (*u.str == '_') { 13107c478bd9Sstevel@tonic-gate u.str = iob_getvar(u.str + 1, 13117c478bd9Sstevel@tonic-gate paramlen - 1); 13127c478bd9Sstevel@tonic-gate break; 13137c478bd9Sstevel@tonic-gate } else { 13147c478bd9Sstevel@tonic-gate (void) iob_setattr(iob, u.str, 13157c478bd9Sstevel@tonic-gate paramlen); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate p++; 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate format = p; 13237c478bd9Sstevel@tonic-gate continue; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate case '*': 13267c478bd9Sstevel@tonic-gate width = (size_t)(uint_t)VA_ARG(ap, int); 13277c478bd9Sstevel@tonic-gate goto fmt_switch; 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate case '%': 13307c478bd9Sstevel@tonic-gate u.str = "%"; 13317c478bd9Sstevel@tonic-gate break; 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate case '?': 13347c478bd9Sstevel@tonic-gate width = sizeof (uintptr_t) * 2; 13357c478bd9Sstevel@tonic-gate goto fmt_switch; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate case '#': 13387c478bd9Sstevel@tonic-gate f_alt = TRUE; 13397c478bd9Sstevel@tonic-gate goto fmt_switch; 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate case '+': 13427c478bd9Sstevel@tonic-gate flags |= NTOS_SIGNPOS; 13437c478bd9Sstevel@tonic-gate goto fmt_switch; 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate case '-': 13467c478bd9Sstevel@tonic-gate f_left = TRUE; 13477c478bd9Sstevel@tonic-gate goto fmt_switch; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate default: 13507c478bd9Sstevel@tonic-gate c[0] = p[0]; 13517c478bd9Sstevel@tonic-gate u.str = c; 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate len = u.str != NULL ? strlen(u.str) : 0; 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate if (len + altlen > width) 13577c478bd9Sstevel@tonic-gate width = len + altlen; 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate /* 13607c478bd9Sstevel@tonic-gate * If the string and the option altstr won't fit on this line 13617c478bd9Sstevel@tonic-gate * and auto-wrap is set (default), skip to the next line. 13627c478bd9Sstevel@tonic-gate */ 13637c478bd9Sstevel@tonic-gate if (IOB_WRAPNOW(iob, width)) 13647c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * Optionally add whitespace or zeroes prefixing the value if 13687c478bd9Sstevel@tonic-gate * we haven't filled the minimum width and we're right-aligned. 13697c478bd9Sstevel@tonic-gate */ 13707c478bd9Sstevel@tonic-gate if (len < (width - altlen) && f_left == FALSE) { 13717c478bd9Sstevel@tonic-gate mdb_iob_fill(iob, f_zfill ? '0' : ' ', 13727c478bd9Sstevel@tonic-gate width - altlen - len); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * Print the alternate string if it's a prefix, and then 13777c478bd9Sstevel@tonic-gate * print the value string itself. 13787c478bd9Sstevel@tonic-gate */ 13797c478bd9Sstevel@tonic-gate if (altstr != NULL && f_altsuff == FALSE) 13807c478bd9Sstevel@tonic-gate mdb_iob_nputs(iob, altstr, altlen); 13817c478bd9Sstevel@tonic-gate if (len != 0) 13827c478bd9Sstevel@tonic-gate mdb_iob_nputs(iob, u.str, len); 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate /* 13857c478bd9Sstevel@tonic-gate * If we have an alternate string and it's a suffix, print it. 13867c478bd9Sstevel@tonic-gate */ 13877c478bd9Sstevel@tonic-gate if (altstr != NULL && f_altsuff == TRUE) 13887c478bd9Sstevel@tonic-gate mdb_iob_nputs(iob, altstr, altlen); 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate /* 13917c478bd9Sstevel@tonic-gate * Finally, if we haven't filled the field width and we're 13927c478bd9Sstevel@tonic-gate * left-aligned, pad out the rest with whitespace. 13937c478bd9Sstevel@tonic-gate */ 13947c478bd9Sstevel@tonic-gate if ((len + altlen) < width && f_left == TRUE) 13957c478bd9Sstevel@tonic-gate mdb_iob_ws(iob, width - altlen - len); 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate format = (*p != '\0') ? ++p : p; 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* 14017c478bd9Sstevel@tonic-gate * If there's anything left in the format string, output it now 14027c478bd9Sstevel@tonic-gate */ 14037c478bd9Sstevel@tonic-gate if (*format != '\0') { 14047c478bd9Sstevel@tonic-gate len = strlen(format); 14057c478bd9Sstevel@tonic-gate if (IOB_WRAPNOW(iob, len) && *format != '\n') 14067c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 14077c478bd9Sstevel@tonic-gate mdb_iob_nputs(iob, format, len); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate void 14127c478bd9Sstevel@tonic-gate mdb_iob_vprintf(mdb_iob_t *iob, const char *format, va_list alist) 14137c478bd9Sstevel@tonic-gate { 14147c478bd9Sstevel@tonic-gate varglist_t ap = { VAT_VARARGS }; 14157c478bd9Sstevel@tonic-gate va_copy(ap.val_valist, alist); 14167c478bd9Sstevel@tonic-gate iob_doprnt(iob, format, &ap); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate void 14207c478bd9Sstevel@tonic-gate mdb_iob_aprintf(mdb_iob_t *iob, const char *format, const mdb_arg_t *argv) 14217c478bd9Sstevel@tonic-gate { 14227c478bd9Sstevel@tonic-gate varglist_t ap = { VAT_ARGVEC }; 14237c478bd9Sstevel@tonic-gate ap.val_argv = argv; 14247c478bd9Sstevel@tonic-gate iob_doprnt(iob, format, &ap); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate void 14287c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb_iob_t *iob, const char *format, ...) 14297c478bd9Sstevel@tonic-gate { 14307c478bd9Sstevel@tonic-gate va_list alist; 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate va_start(alist, format); 14337c478bd9Sstevel@tonic-gate mdb_iob_vprintf(iob, format, alist); 14347c478bd9Sstevel@tonic-gate va_end(alist); 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate /* 14387c478bd9Sstevel@tonic-gate * In order to handle the sprintf family of functions, we define a special 14397c478bd9Sstevel@tonic-gate * i/o backend known as a "sprintf buf" (or spbuf for short). This back end 14407c478bd9Sstevel@tonic-gate * provides an IOP_WRITE entry point that concatenates each buffer sent from 14417c478bd9Sstevel@tonic-gate * mdb_iob_flush() onto the caller's buffer until the caller's buffer is 14427c478bd9Sstevel@tonic-gate * exhausted. We also keep an absolute count of how many bytes were sent to 14437c478bd9Sstevel@tonic-gate * this function during the lifetime of the snprintf call. This allows us 14447c478bd9Sstevel@tonic-gate * to provide the ability to (1) return the total size required for the given 14457c478bd9Sstevel@tonic-gate * format string and argument list, and (2) support a call to snprintf with a 14467c478bd9Sstevel@tonic-gate * NULL buffer argument with no special case code elsewhere. 14477c478bd9Sstevel@tonic-gate */ 14487c478bd9Sstevel@tonic-gate static ssize_t 14497c478bd9Sstevel@tonic-gate spbuf_write(mdb_io_t *io, const void *buf, size_t buflen) 14507c478bd9Sstevel@tonic-gate { 14517c478bd9Sstevel@tonic-gate spbuf_t *spb = io->io_data; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if (spb->spb_bufsiz != 0) { 14547c478bd9Sstevel@tonic-gate size_t n = MIN(spb->spb_bufsiz, buflen); 14557c478bd9Sstevel@tonic-gate bcopy(buf, spb->spb_buf, n); 14567c478bd9Sstevel@tonic-gate spb->spb_buf += n; 14577c478bd9Sstevel@tonic-gate spb->spb_bufsiz -= n; 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate spb->spb_total += buflen; 14617c478bd9Sstevel@tonic-gate return (buflen); 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate static const mdb_io_ops_t spbuf_ops = { 14657c478bd9Sstevel@tonic-gate no_io_read, 14667c478bd9Sstevel@tonic-gate spbuf_write, 14677c478bd9Sstevel@tonic-gate no_io_seek, 14687c478bd9Sstevel@tonic-gate no_io_ctl, 14697c478bd9Sstevel@tonic-gate no_io_close, 14707c478bd9Sstevel@tonic-gate no_io_name, 14717c478bd9Sstevel@tonic-gate no_io_link, 14727c478bd9Sstevel@tonic-gate no_io_unlink, 14737c478bd9Sstevel@tonic-gate no_io_setattr, 14747c478bd9Sstevel@tonic-gate no_io_suspend, 14757c478bd9Sstevel@tonic-gate no_io_resume 14767c478bd9Sstevel@tonic-gate }; 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* 14797c478bd9Sstevel@tonic-gate * The iob_spb_create function initializes an iob suitable for snprintf calls, 14807c478bd9Sstevel@tonic-gate * a spbuf i/o backend, and the spbuf private data, and then glues these 14817c478bd9Sstevel@tonic-gate * objects together. The caller (either vsnprintf or asnprintf below) is 14827c478bd9Sstevel@tonic-gate * expected to have allocated the various structures on their stack. 14837c478bd9Sstevel@tonic-gate */ 14847c478bd9Sstevel@tonic-gate static void 14857c478bd9Sstevel@tonic-gate iob_spb_create(mdb_iob_t *iob, char *iob_buf, size_t iob_len, 14867c478bd9Sstevel@tonic-gate mdb_io_t *io, spbuf_t *spb, char *spb_buf, size_t spb_len) 14877c478bd9Sstevel@tonic-gate { 14887c478bd9Sstevel@tonic-gate spb->spb_buf = spb_buf; 14897c478bd9Sstevel@tonic-gate spb->spb_bufsiz = spb_len; 14907c478bd9Sstevel@tonic-gate spb->spb_total = 0; 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate io->io_ops = &spbuf_ops; 14937c478bd9Sstevel@tonic-gate io->io_data = spb; 14947c478bd9Sstevel@tonic-gate io->io_next = NULL; 14957c478bd9Sstevel@tonic-gate io->io_refcnt = 1; 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate iob->iob_buf = iob_buf; 14987c478bd9Sstevel@tonic-gate iob->iob_bufsiz = iob_len; 14997c478bd9Sstevel@tonic-gate iob->iob_bufp = iob_buf; 15007c478bd9Sstevel@tonic-gate iob->iob_nbytes = 0; 15017c478bd9Sstevel@tonic-gate iob->iob_nlines = 0; 15027c478bd9Sstevel@tonic-gate iob->iob_lineno = 1; 15037c478bd9Sstevel@tonic-gate iob->iob_rows = MDB_IOB_DEFROWS; 15047c478bd9Sstevel@tonic-gate iob->iob_cols = iob_len; 15057c478bd9Sstevel@tonic-gate iob->iob_tabstop = MDB_IOB_DEFTAB; 15067c478bd9Sstevel@tonic-gate iob->iob_margin = MDB_IOB_DEFMARGIN; 15077c478bd9Sstevel@tonic-gate iob->iob_flags = MDB_IOB_WRONLY; 15087c478bd9Sstevel@tonic-gate iob->iob_iop = io; 15097c478bd9Sstevel@tonic-gate iob->iob_pgp = NULL; 15107c478bd9Sstevel@tonic-gate iob->iob_next = NULL; 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15147c478bd9Sstevel@tonic-gate ssize_t 15157c478bd9Sstevel@tonic-gate null_io_write(mdb_io_t *io, const void *buf, size_t nbytes) 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate return (nbytes); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate static const mdb_io_ops_t null_ops = { 15217c478bd9Sstevel@tonic-gate no_io_read, 15227c478bd9Sstevel@tonic-gate null_io_write, 15237c478bd9Sstevel@tonic-gate no_io_seek, 15247c478bd9Sstevel@tonic-gate no_io_ctl, 15257c478bd9Sstevel@tonic-gate no_io_close, 15267c478bd9Sstevel@tonic-gate no_io_name, 15277c478bd9Sstevel@tonic-gate no_io_link, 15287c478bd9Sstevel@tonic-gate no_io_unlink, 15297c478bd9Sstevel@tonic-gate no_io_setattr, 15307c478bd9Sstevel@tonic-gate no_io_suspend, 15317c478bd9Sstevel@tonic-gate no_io_resume 15327c478bd9Sstevel@tonic-gate }; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate mdb_io_t * 15357c478bd9Sstevel@tonic-gate mdb_nullio_create(void) 15367c478bd9Sstevel@tonic-gate { 15377c478bd9Sstevel@tonic-gate static mdb_io_t null_io = { 15387c478bd9Sstevel@tonic-gate &null_ops, 15397c478bd9Sstevel@tonic-gate NULL, 15407c478bd9Sstevel@tonic-gate NULL, 15417c478bd9Sstevel@tonic-gate 1 15427c478bd9Sstevel@tonic-gate }; 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate return (&null_io); 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate size_t 15487c478bd9Sstevel@tonic-gate mdb_iob_vsnprintf(char *buf, size_t nbytes, const char *format, va_list alist) 15497c478bd9Sstevel@tonic-gate { 15507c478bd9Sstevel@tonic-gate varglist_t ap = { VAT_VARARGS }; 15517c478bd9Sstevel@tonic-gate char iob_buf[64]; 15527c478bd9Sstevel@tonic-gate mdb_iob_t iob; 15537c478bd9Sstevel@tonic-gate mdb_io_t io; 15547c478bd9Sstevel@tonic-gate spbuf_t spb; 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate ASSERT(buf != NULL || nbytes == 0); 15577c478bd9Sstevel@tonic-gate iob_spb_create(&iob, iob_buf, sizeof (iob_buf), &io, &spb, buf, nbytes); 15587c478bd9Sstevel@tonic-gate va_copy(ap.val_valist, alist); 15597c478bd9Sstevel@tonic-gate iob_doprnt(&iob, format, &ap); 15607c478bd9Sstevel@tonic-gate mdb_iob_flush(&iob); 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate if (spb.spb_bufsiz != 0) 15637c478bd9Sstevel@tonic-gate *spb.spb_buf = '\0'; 15647c478bd9Sstevel@tonic-gate else if (buf != NULL && nbytes > 0) 15657c478bd9Sstevel@tonic-gate *--spb.spb_buf = '\0'; 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate return (spb.spb_total); 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate size_t 15717c478bd9Sstevel@tonic-gate mdb_iob_asnprintf(char *buf, size_t nbytes, const char *format, 15727c478bd9Sstevel@tonic-gate const mdb_arg_t *argv) 15737c478bd9Sstevel@tonic-gate { 15747c478bd9Sstevel@tonic-gate varglist_t ap = { VAT_ARGVEC }; 15757c478bd9Sstevel@tonic-gate char iob_buf[64]; 15767c478bd9Sstevel@tonic-gate mdb_iob_t iob; 15777c478bd9Sstevel@tonic-gate mdb_io_t io; 15787c478bd9Sstevel@tonic-gate spbuf_t spb; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate ASSERT(buf != NULL || nbytes == 0); 15817c478bd9Sstevel@tonic-gate iob_spb_create(&iob, iob_buf, sizeof (iob_buf), &io, &spb, buf, nbytes); 15827c478bd9Sstevel@tonic-gate ap.val_argv = argv; 15837c478bd9Sstevel@tonic-gate iob_doprnt(&iob, format, &ap); 15847c478bd9Sstevel@tonic-gate mdb_iob_flush(&iob); 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate if (spb.spb_bufsiz != 0) 15877c478bd9Sstevel@tonic-gate *spb.spb_buf = '\0'; 15887c478bd9Sstevel@tonic-gate else if (buf != NULL && nbytes > 0) 15897c478bd9Sstevel@tonic-gate *--spb.spb_buf = '\0'; 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate return (spb.spb_total); 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 15957c478bd9Sstevel@tonic-gate size_t 15967c478bd9Sstevel@tonic-gate mdb_iob_snprintf(char *buf, size_t nbytes, const char *format, ...) 15977c478bd9Sstevel@tonic-gate { 15987c478bd9Sstevel@tonic-gate va_list alist; 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate va_start(alist, format); 16017c478bd9Sstevel@tonic-gate nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist); 16027c478bd9Sstevel@tonic-gate va_end(alist); 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate return (nbytes); 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate void 16087c478bd9Sstevel@tonic-gate mdb_iob_nputs(mdb_iob_t *iob, const char *s, size_t nbytes) 16097c478bd9Sstevel@tonic-gate { 16107c478bd9Sstevel@tonic-gate size_t m, n, nleft = nbytes; 16117c478bd9Sstevel@tonic-gate const char *p, *q = s; 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate if (nbytes == 0) 16167c478bd9Sstevel@tonic-gate return; /* Return immediately if there is no work to do */ 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate /* 16197c478bd9Sstevel@tonic-gate * If the string contains embedded newlines or tabs, invoke ourself 16207c478bd9Sstevel@tonic-gate * recursively for each string component, followed by a call to the 16217c478bd9Sstevel@tonic-gate * newline or tab routine. This insures that strings with these 16227c478bd9Sstevel@tonic-gate * characters obey our wrapping and indenting rules, and that strings 16237c478bd9Sstevel@tonic-gate * with embedded newlines are flushed after each newline, allowing 16247c478bd9Sstevel@tonic-gate * the output pager to take over if it is enabled. 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate while ((p = strnpbrk(q, "\t\n", nleft)) != NULL) { 16277c478bd9Sstevel@tonic-gate if (p > q) 16287c478bd9Sstevel@tonic-gate mdb_iob_nputs(iob, q, (size_t)(p - q)); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate if (*p == '\t') 16317c478bd9Sstevel@tonic-gate mdb_iob_tab(iob); 16327c478bd9Sstevel@tonic-gate else 16337c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate nleft -= (size_t)(p - q) + 1; /* Update byte count */ 16367c478bd9Sstevel@tonic-gate q = p + 1; /* Advance past delimiter */ 16377c478bd9Sstevel@tonic-gate } 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate /* 16407c478bd9Sstevel@tonic-gate * For a given string component, we determine how many bytes (n) we can 16417c478bd9Sstevel@tonic-gate * copy into our buffer (limited by either cols or bufsiz depending 16427c478bd9Sstevel@tonic-gate * on whether AUTOWRAP is on), copy a chunk into the buffer, and 16437c478bd9Sstevel@tonic-gate * flush the buffer if we reach the end of a line. 16447c478bd9Sstevel@tonic-gate */ 16457c478bd9Sstevel@tonic-gate while (nleft != 0) { 16467c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_AUTOWRAP) { 16477c478bd9Sstevel@tonic-gate ASSERT(iob->iob_cols >= iob->iob_nbytes); 16487c478bd9Sstevel@tonic-gate n = iob->iob_cols - iob->iob_nbytes; 16497c478bd9Sstevel@tonic-gate } else { 16507c478bd9Sstevel@tonic-gate ASSERT(iob->iob_bufsiz >= iob->iob_nbytes); 16517c478bd9Sstevel@tonic-gate n = iob->iob_bufsiz - iob->iob_nbytes; 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate m = MIN(nleft, n); /* copy at most n bytes in this pass */ 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate bcopy(q, iob->iob_bufp, m); 16577c478bd9Sstevel@tonic-gate nleft -= m; 16587c478bd9Sstevel@tonic-gate q += m; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate iob->iob_bufp += m; 16617c478bd9Sstevel@tonic-gate iob->iob_nbytes += m; 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate if (m == n && nleft != 0) { 16647c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_AUTOWRAP) 16657c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 16667c478bd9Sstevel@tonic-gate else 16677c478bd9Sstevel@tonic-gate mdb_iob_flush(iob); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate void 16737c478bd9Sstevel@tonic-gate mdb_iob_puts(mdb_iob_t *iob, const char *s) 16747c478bd9Sstevel@tonic-gate { 16757c478bd9Sstevel@tonic-gate mdb_iob_nputs(iob, s, strlen(s)); 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate void 16797c478bd9Sstevel@tonic-gate mdb_iob_putc(mdb_iob_t *iob, int c) 16807c478bd9Sstevel@tonic-gate { 16817c478bd9Sstevel@tonic-gate mdb_iob_fill(iob, c, 1); 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate void 16857c478bd9Sstevel@tonic-gate mdb_iob_tab(mdb_iob_t *iob) 16867c478bd9Sstevel@tonic-gate { 16877c478bd9Sstevel@tonic-gate ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate if (iob->iob_tabstop != 0) { 16907c478bd9Sstevel@tonic-gate /* 16917c478bd9Sstevel@tonic-gate * Round up to the next multiple of the tabstop. If this puts 16927c478bd9Sstevel@tonic-gate * us off the end of the line, just insert a newline; otherwise 16937c478bd9Sstevel@tonic-gate * insert sufficient whitespace to reach position n. 16947c478bd9Sstevel@tonic-gate */ 16957c478bd9Sstevel@tonic-gate size_t n = (iob->iob_nbytes + iob->iob_tabstop) / 16967c478bd9Sstevel@tonic-gate iob->iob_tabstop * iob->iob_tabstop; 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate if (n < iob->iob_cols) 16997c478bd9Sstevel@tonic-gate mdb_iob_fill(iob, ' ', n - iob->iob_nbytes); 17007c478bd9Sstevel@tonic-gate else 17017c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate void 17067c478bd9Sstevel@tonic-gate mdb_iob_fill(mdb_iob_t *iob, int c, size_t nfill) 17077c478bd9Sstevel@tonic-gate { 17087c478bd9Sstevel@tonic-gate size_t i, m, n; 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate while (nfill != 0) { 17137c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_AUTOWRAP) { 17147c478bd9Sstevel@tonic-gate ASSERT(iob->iob_cols >= iob->iob_nbytes); 17157c478bd9Sstevel@tonic-gate n = iob->iob_cols - iob->iob_nbytes; 17167c478bd9Sstevel@tonic-gate } else { 17177c478bd9Sstevel@tonic-gate ASSERT(iob->iob_bufsiz >= iob->iob_nbytes); 17187c478bd9Sstevel@tonic-gate n = iob->iob_bufsiz - iob->iob_nbytes; 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate m = MIN(nfill, n); /* fill at most n bytes in this pass */ 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate for (i = 0; i < m; i++) 17247c478bd9Sstevel@tonic-gate *iob->iob_bufp++ = (char)c; 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate iob->iob_nbytes += m; 17277c478bd9Sstevel@tonic-gate nfill -= m; 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate if (m == n && nfill != 0) { 17307c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_AUTOWRAP) 17317c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 17327c478bd9Sstevel@tonic-gate else 17337c478bd9Sstevel@tonic-gate mdb_iob_flush(iob); 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate void 17397c478bd9Sstevel@tonic-gate mdb_iob_ws(mdb_iob_t *iob, size_t n) 17407c478bd9Sstevel@tonic-gate { 17417c478bd9Sstevel@tonic-gate if (iob->iob_nbytes + n < iob->iob_cols) 17427c478bd9Sstevel@tonic-gate mdb_iob_fill(iob, ' ', n); 17437c478bd9Sstevel@tonic-gate else 17447c478bd9Sstevel@tonic-gate mdb_iob_nl(iob); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate void 17487c478bd9Sstevel@tonic-gate mdb_iob_nl(mdb_iob_t *iob) 17497c478bd9Sstevel@tonic-gate { 17507c478bd9Sstevel@tonic-gate ASSERT(iob->iob_flags & MDB_IOB_WRONLY); 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate if (iob->iob_nbytes == iob->iob_bufsiz) 17537c478bd9Sstevel@tonic-gate mdb_iob_flush(iob); 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate *iob->iob_bufp++ = '\n'; 17567c478bd9Sstevel@tonic-gate iob->iob_nbytes++; 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate mdb_iob_flush(iob); 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate ssize_t 17627c478bd9Sstevel@tonic-gate mdb_iob_ngets(mdb_iob_t *iob, char *buf, size_t n) 17637c478bd9Sstevel@tonic-gate { 17647c478bd9Sstevel@tonic-gate ssize_t resid = n - 1; 17657c478bd9Sstevel@tonic-gate ssize_t len; 17667c478bd9Sstevel@tonic-gate int c; 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_EOF)) 17697c478bd9Sstevel@tonic-gate return (EOF); /* can't gets a write buf or a read buf at EOF */ 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate if (n == 0) 17727c478bd9Sstevel@tonic-gate return (0); /* we need room for a terminating \0 */ 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate while (resid != 0) { 17757c478bd9Sstevel@tonic-gate if (iob->iob_nbytes == 0 && iob_read(iob, iob->iob_iop) <= 0) 17767c478bd9Sstevel@tonic-gate goto done; /* failed to refill buffer */ 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate for (len = MIN(iob->iob_nbytes, resid); len != 0; len--) { 17797c478bd9Sstevel@tonic-gate c = *iob->iob_bufp++; 17807c478bd9Sstevel@tonic-gate iob->iob_nbytes--; 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate if (c == EOF || c == '\n') 17837c478bd9Sstevel@tonic-gate goto done; 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate *buf++ = (char)c; 17867c478bd9Sstevel@tonic-gate resid--; 17877c478bd9Sstevel@tonic-gate } 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate done: 17907c478bd9Sstevel@tonic-gate *buf = '\0'; 17917c478bd9Sstevel@tonic-gate return (n - resid - 1); 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate int 17957c478bd9Sstevel@tonic-gate mdb_iob_getc(mdb_iob_t *iob) 17967c478bd9Sstevel@tonic-gate { 17977c478bd9Sstevel@tonic-gate int c; 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_EOF | MDB_IOB_ERR)) 18007c478bd9Sstevel@tonic-gate return (EOF); /* can't getc if write-only, EOF, or error bit */ 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate if (iob->iob_nbytes == 0 && iob_read(iob, iob->iob_iop) <= 0) 18037c478bd9Sstevel@tonic-gate return (EOF); /* failed to refill buffer */ 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate c = (uchar_t)*iob->iob_bufp++; 18067c478bd9Sstevel@tonic-gate iob->iob_nbytes--; 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate return (c); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate int 18127c478bd9Sstevel@tonic-gate mdb_iob_ungetc(mdb_iob_t *iob, int c) 18137c478bd9Sstevel@tonic-gate { 18147c478bd9Sstevel@tonic-gate if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_ERR)) 18157c478bd9Sstevel@tonic-gate return (EOF); /* can't ungetc if write-only or error bit set */ 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate if (c == EOF || iob->iob_nbytes == iob->iob_bufsiz) 18187c478bd9Sstevel@tonic-gate return (EOF); /* can't ungetc EOF, or ungetc if buffer full */ 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate *--iob->iob_bufp = (char)c; 18217c478bd9Sstevel@tonic-gate iob->iob_nbytes++; 18227c478bd9Sstevel@tonic-gate iob->iob_flags &= ~MDB_IOB_EOF; 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate return (c); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate int 18287c478bd9Sstevel@tonic-gate mdb_iob_eof(mdb_iob_t *iob) 18297c478bd9Sstevel@tonic-gate { 18307c478bd9Sstevel@tonic-gate return ((iob->iob_flags & (MDB_IOB_RDONLY | MDB_IOB_EOF)) == 18317c478bd9Sstevel@tonic-gate (MDB_IOB_RDONLY | MDB_IOB_EOF)); 18327c478bd9Sstevel@tonic-gate } 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate int 18357c478bd9Sstevel@tonic-gate mdb_iob_err(mdb_iob_t *iob) 18367c478bd9Sstevel@tonic-gate { 18377c478bd9Sstevel@tonic-gate return ((iob->iob_flags & MDB_IOB_ERR) == MDB_IOB_ERR); 18387c478bd9Sstevel@tonic-gate } 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate ssize_t 18417c478bd9Sstevel@tonic-gate mdb_iob_read(mdb_iob_t *iob, void *buf, size_t n) 18427c478bd9Sstevel@tonic-gate { 18437c478bd9Sstevel@tonic-gate ssize_t resid = n; 18447c478bd9Sstevel@tonic-gate ssize_t len; 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate if (iob->iob_flags & (MDB_IOB_WRONLY | MDB_IOB_EOF | MDB_IOB_ERR)) 18477c478bd9Sstevel@tonic-gate return (0); /* can't read if write-only, eof, or error */ 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate while (resid != 0) { 18507c478bd9Sstevel@tonic-gate if (iob->iob_nbytes == 0 && iob_read(iob, iob->iob_iop) <= 0) 18517c478bd9Sstevel@tonic-gate break; /* failed to refill buffer */ 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate len = MIN(resid, iob->iob_nbytes); 18547c478bd9Sstevel@tonic-gate bcopy(iob->iob_bufp, buf, len); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate iob->iob_bufp += len; 18577c478bd9Sstevel@tonic-gate iob->iob_nbytes -= len; 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate buf = (char *)buf + len; 18607c478bd9Sstevel@tonic-gate resid -= len; 18617c478bd9Sstevel@tonic-gate } 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate return (n - resid); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate /* 18677c478bd9Sstevel@tonic-gate * For now, all binary writes are performed unbuffered. This has the 18687c478bd9Sstevel@tonic-gate * side effect that the pager will not be triggered by mdb_iob_write. 18697c478bd9Sstevel@tonic-gate */ 18707c478bd9Sstevel@tonic-gate ssize_t 18717c478bd9Sstevel@tonic-gate mdb_iob_write(mdb_iob_t *iob, const void *buf, size_t n) 18727c478bd9Sstevel@tonic-gate { 18737c478bd9Sstevel@tonic-gate ssize_t ret; 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_ERR) 18767c478bd9Sstevel@tonic-gate return (set_errno(EIO)); 18777c478bd9Sstevel@tonic-gate if (iob->iob_flags & MDB_IOB_RDONLY) 18787c478bd9Sstevel@tonic-gate return (set_errno(EMDB_IORO)); 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate mdb_iob_flush(iob); 18817c478bd9Sstevel@tonic-gate ret = iob_write(iob, iob->iob_iop, buf, n); 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate if (ret < 0 && iob == mdb.m_out) 18847c478bd9Sstevel@tonic-gate longjmp(mdb.m_frame->f_pcb, MDB_ERR_OUTPUT); 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate return (ret); 18877c478bd9Sstevel@tonic-gate } 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate int 18907c478bd9Sstevel@tonic-gate mdb_iob_ctl(mdb_iob_t *iob, int req, void *arg) 18917c478bd9Sstevel@tonic-gate { 18927c478bd9Sstevel@tonic-gate return (IOP_CTL(iob->iob_iop, req, arg)); 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate const char * 18967c478bd9Sstevel@tonic-gate mdb_iob_name(mdb_iob_t *iob) 18977c478bd9Sstevel@tonic-gate { 18987c478bd9Sstevel@tonic-gate if (iob == NULL) 18997c478bd9Sstevel@tonic-gate return ("<NULL>"); 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate return (IOP_NAME(iob->iob_iop)); 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate size_t 19057c478bd9Sstevel@tonic-gate mdb_iob_lineno(mdb_iob_t *iob) 19067c478bd9Sstevel@tonic-gate { 19077c478bd9Sstevel@tonic-gate return (iob->iob_lineno); 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate size_t 19117c478bd9Sstevel@tonic-gate mdb_iob_gettabstop(mdb_iob_t *iob) 19127c478bd9Sstevel@tonic-gate { 19137c478bd9Sstevel@tonic-gate return (iob->iob_tabstop); 19147c478bd9Sstevel@tonic-gate } 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate size_t 19177c478bd9Sstevel@tonic-gate mdb_iob_getmargin(mdb_iob_t *iob) 19187c478bd9Sstevel@tonic-gate { 19197c478bd9Sstevel@tonic-gate return (iob->iob_margin); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate mdb_io_t * 19237c478bd9Sstevel@tonic-gate mdb_io_hold(mdb_io_t *io) 19247c478bd9Sstevel@tonic-gate { 19257c478bd9Sstevel@tonic-gate io->io_refcnt++; 19267c478bd9Sstevel@tonic-gate return (io); 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate void 19307c478bd9Sstevel@tonic-gate mdb_io_rele(mdb_io_t *io) 19317c478bd9Sstevel@tonic-gate { 19327c478bd9Sstevel@tonic-gate ASSERT(io->io_refcnt != 0); 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate if (--io->io_refcnt == 0) { 19357c478bd9Sstevel@tonic-gate IOP_CLOSE(io); 19367c478bd9Sstevel@tonic-gate mdb_free(io, sizeof (mdb_io_t)); 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate void 19417c478bd9Sstevel@tonic-gate mdb_io_destroy(mdb_io_t *io) 19427c478bd9Sstevel@tonic-gate { 19437c478bd9Sstevel@tonic-gate ASSERT(io->io_refcnt == 0); 19447c478bd9Sstevel@tonic-gate IOP_CLOSE(io); 19457c478bd9Sstevel@tonic-gate mdb_free(io, sizeof (mdb_io_t)); 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate 19487c478bd9Sstevel@tonic-gate void 19497c478bd9Sstevel@tonic-gate mdb_iob_stack_create(mdb_iob_stack_t *stk) 19507c478bd9Sstevel@tonic-gate { 19517c478bd9Sstevel@tonic-gate stk->stk_top = NULL; 19527c478bd9Sstevel@tonic-gate stk->stk_size = 0; 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate void 19567c478bd9Sstevel@tonic-gate mdb_iob_stack_destroy(mdb_iob_stack_t *stk) 19577c478bd9Sstevel@tonic-gate { 19587c478bd9Sstevel@tonic-gate mdb_iob_t *top, *ntop; 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate for (top = stk->stk_top; top != NULL; top = ntop) { 19617c478bd9Sstevel@tonic-gate ntop = top->iob_next; 19627c478bd9Sstevel@tonic-gate mdb_iob_destroy(top); 19637c478bd9Sstevel@tonic-gate } 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate void 19677c478bd9Sstevel@tonic-gate mdb_iob_stack_push(mdb_iob_stack_t *stk, mdb_iob_t *iob, size_t lineno) 19687c478bd9Sstevel@tonic-gate { 19697c478bd9Sstevel@tonic-gate iob->iob_lineno = lineno; 19707c478bd9Sstevel@tonic-gate iob->iob_next = stk->stk_top; 19717c478bd9Sstevel@tonic-gate stk->stk_top = iob; 19727c478bd9Sstevel@tonic-gate stk->stk_size++; 19737c478bd9Sstevel@tonic-gate yylineno = 1; 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate mdb_iob_t * 19777c478bd9Sstevel@tonic-gate mdb_iob_stack_pop(mdb_iob_stack_t *stk) 19787c478bd9Sstevel@tonic-gate { 19797c478bd9Sstevel@tonic-gate mdb_iob_t *top = stk->stk_top; 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate ASSERT(top != NULL); 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate stk->stk_top = top->iob_next; 19847c478bd9Sstevel@tonic-gate top->iob_next = NULL; 19857c478bd9Sstevel@tonic-gate stk->stk_size--; 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate return (top); 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate size_t 19917c478bd9Sstevel@tonic-gate mdb_iob_stack_size(mdb_iob_stack_t *stk) 19927c478bd9Sstevel@tonic-gate { 19937c478bd9Sstevel@tonic-gate return (stk->stk_size); 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* 19977c478bd9Sstevel@tonic-gate * Stub functions for i/o backend implementors: these stubs either act as 19987c478bd9Sstevel@tonic-gate * pass-through no-ops or return ENOTSUP as appropriate. 19997c478bd9Sstevel@tonic-gate */ 20007c478bd9Sstevel@tonic-gate ssize_t 20017c478bd9Sstevel@tonic-gate no_io_read(mdb_io_t *io, void *buf, size_t nbytes) 20027c478bd9Sstevel@tonic-gate { 20037c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20047c478bd9Sstevel@tonic-gate return (IOP_READ(io->io_next, buf, nbytes)); 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate return (set_errno(EMDB_IOWO)); 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate ssize_t 20107c478bd9Sstevel@tonic-gate no_io_write(mdb_io_t *io, const void *buf, size_t nbytes) 20117c478bd9Sstevel@tonic-gate { 20127c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20137c478bd9Sstevel@tonic-gate return (IOP_WRITE(io->io_next, buf, nbytes)); 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate return (set_errno(EMDB_IORO)); 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate off64_t 20197c478bd9Sstevel@tonic-gate no_io_seek(mdb_io_t *io, off64_t offset, int whence) 20207c478bd9Sstevel@tonic-gate { 20217c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20227c478bd9Sstevel@tonic-gate return (IOP_SEEK(io->io_next, offset, whence)); 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate int 20287c478bd9Sstevel@tonic-gate no_io_ctl(mdb_io_t *io, int req, void *arg) 20297c478bd9Sstevel@tonic-gate { 20307c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20317c478bd9Sstevel@tonic-gate return (IOP_CTL(io->io_next, req, arg)); 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 20347c478bd9Sstevel@tonic-gate } 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20377c478bd9Sstevel@tonic-gate void 20387c478bd9Sstevel@tonic-gate no_io_close(mdb_io_t *io) 20397c478bd9Sstevel@tonic-gate { 20407c478bd9Sstevel@tonic-gate /* 20417c478bd9Sstevel@tonic-gate * Note that we do not propagate IOP_CLOSE down the io stack. IOP_CLOSE should 20427c478bd9Sstevel@tonic-gate * only be called by mdb_io_rele when an io's reference count has gone to zero. 20437c478bd9Sstevel@tonic-gate */ 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate const char * 20477c478bd9Sstevel@tonic-gate no_io_name(mdb_io_t *io) 20487c478bd9Sstevel@tonic-gate { 20497c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20507c478bd9Sstevel@tonic-gate return (IOP_NAME(io->io_next)); 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate return ("(anonymous)"); 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate void 20567c478bd9Sstevel@tonic-gate no_io_link(mdb_io_t *io, mdb_iob_t *iob) 20577c478bd9Sstevel@tonic-gate { 20587c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20597c478bd9Sstevel@tonic-gate IOP_LINK(io->io_next, iob); 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate void 20637c478bd9Sstevel@tonic-gate no_io_unlink(mdb_io_t *io, mdb_iob_t *iob) 20647c478bd9Sstevel@tonic-gate { 20657c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20667c478bd9Sstevel@tonic-gate IOP_UNLINK(io->io_next, iob); 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate int 20707c478bd9Sstevel@tonic-gate no_io_setattr(mdb_io_t *io, int req, uint_t attrs) 20717c478bd9Sstevel@tonic-gate { 20727c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20737c478bd9Sstevel@tonic-gate return (IOP_SETATTR(io->io_next, req, attrs)); 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate void 20797c478bd9Sstevel@tonic-gate no_io_suspend(mdb_io_t *io) 20807c478bd9Sstevel@tonic-gate { 20817c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20827c478bd9Sstevel@tonic-gate IOP_SUSPEND(io->io_next); 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate void 20867c478bd9Sstevel@tonic-gate no_io_resume(mdb_io_t *io) 20877c478bd9Sstevel@tonic-gate { 20887c478bd9Sstevel@tonic-gate if (io->io_next != NULL) 20897c478bd9Sstevel@tonic-gate IOP_RESUME(io->io_next); 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate /* 20937c478bd9Sstevel@tonic-gate * Iterate over the varargs. The first item indicates the mode: 20947c478bd9Sstevel@tonic-gate * MDB_TBL_PRNT 20957c478bd9Sstevel@tonic-gate * pull out the next vararg as a const char * and pass it and the 20967c478bd9Sstevel@tonic-gate * remaining varargs to iob_doprnt; if we want to print the column, 20977c478bd9Sstevel@tonic-gate * direct the output to mdb.m_out otherwise direct it to mdb.m_null 20987c478bd9Sstevel@tonic-gate * 20997c478bd9Sstevel@tonic-gate * MDB_TBL_FUNC 21007c478bd9Sstevel@tonic-gate * pull out the next vararg as type mdb_table_print_f and the 21017c478bd9Sstevel@tonic-gate * following one as a void * argument to the function; call the 21027c478bd9Sstevel@tonic-gate * function with the given argument if we want to print the column 21037c478bd9Sstevel@tonic-gate * 21047c478bd9Sstevel@tonic-gate * The second item indicates the flag; if the flag is set in the flags 21057c478bd9Sstevel@tonic-gate * argument, then the column is printed. A flag value of 0 indicates 21067c478bd9Sstevel@tonic-gate * that the column should always be printed. 21077c478bd9Sstevel@tonic-gate */ 21087c478bd9Sstevel@tonic-gate void 21097c478bd9Sstevel@tonic-gate mdb_table_print(uint_t flags, const char *delimeter, ...) 21107c478bd9Sstevel@tonic-gate { 21117c478bd9Sstevel@tonic-gate va_list alist; 21127c478bd9Sstevel@tonic-gate uint_t flg; 21137c478bd9Sstevel@tonic-gate uint_t type; 21147c478bd9Sstevel@tonic-gate const char *fmt; 21157c478bd9Sstevel@tonic-gate mdb_table_print_f *func; 21167c478bd9Sstevel@tonic-gate void *arg; 21177c478bd9Sstevel@tonic-gate mdb_iob_t *out; 21187c478bd9Sstevel@tonic-gate mdb_bool_t first = TRUE; 21197c478bd9Sstevel@tonic-gate mdb_bool_t print; 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate va_start(alist, delimeter); 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate while ((type = va_arg(alist, uint_t)) != MDB_TBL_DONE) { 21247c478bd9Sstevel@tonic-gate flg = va_arg(alist, uint_t); 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate print = flg == 0 || (flg & flags) != 0; 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate if (print) { 21297c478bd9Sstevel@tonic-gate if (first) 21307c478bd9Sstevel@tonic-gate first = FALSE; 21317c478bd9Sstevel@tonic-gate else 21327c478bd9Sstevel@tonic-gate mdb_printf("%s", delimeter); 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate switch (type) { 21367c478bd9Sstevel@tonic-gate case MDB_TBL_PRNT: { 21377c478bd9Sstevel@tonic-gate varglist_t ap = { VAT_VARARGS }; 21387c478bd9Sstevel@tonic-gate fmt = va_arg(alist, const char *); 21397c478bd9Sstevel@tonic-gate out = print ? mdb.m_out : mdb.m_null; 21407c478bd9Sstevel@tonic-gate va_copy(ap.val_valist, alist); 21417c478bd9Sstevel@tonic-gate iob_doprnt(out, fmt, &ap); 21427c478bd9Sstevel@tonic-gate va_end(alist); 21437c478bd9Sstevel@tonic-gate va_copy(alist, ap.val_valist); 21447c478bd9Sstevel@tonic-gate break; 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate case MDB_TBL_FUNC: 21487c478bd9Sstevel@tonic-gate func = va_arg(alist, mdb_table_print_f *); 21497c478bd9Sstevel@tonic-gate arg = va_arg(alist, void *); 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate if (print) 21527c478bd9Sstevel@tonic-gate func(arg); 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate break; 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate default: 21577c478bd9Sstevel@tonic-gate warn("bad format type %x\n", type); 21587c478bd9Sstevel@tonic-gate break; 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate va_end(alist); 21637c478bd9Sstevel@tonic-gate } 2164