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