/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
/*
* MDB uses its own enhanced standard i/o mechanism for all input and output.
* This file provides the underpinnings of this mechanism, including the
* printf-style formatting code, the output pager, and APIs for raw input
* and output. This mechanism is used throughout the debugger for everything
* from simple sprintf and printf-style formatting, to input to the lexer
* and parser, to raw file i/o for reading ELF files. In general, we divide
* our i/o implementation into two parts:
*
* (1) An i/o buffer (mdb_iob_t) provides buffered read or write capabilities,
* as well as access to formatting and the ability to invoke a pager. The
* buffer is constructed explicitly for use in either reading or writing; it
* may not be used for both simultaneously.
*
* (2) Each i/o buffer is associated with an underlying i/o backend (mdb_io_t).
* The backend provides, through an ops-vector, equivalents for the standard
* read, write, lseek, ioctl, and close operations. In addition, the backend
* can provide an IOP_NAME entry point for returning a name for the backend,
* IOP_LINK and IOP_UNLINK entry points that are called when the backend is
* connected or disconnected from an mdb_iob_t, and an IOP_SETATTR entry point
* for manipulating terminal attributes.
*
* The i/o objects themselves are reference counted so that more than one i/o
* buffer may make use of the same i/o backend. In addition, each buffer
* provides the ability to push or pop backends to interpose on input or output
* behavior. We make use of this, for example, to implement interactive
* session logging. Normally, the stdout iob has a backend that is either
* file descriptor 1, or a terminal i/o backend associated with the tty.
* However, we can push a log i/o backend on top that multiplexes stdout to
* the original back-end and another backend that writes to a log file. The
* use of i/o backends is also used for simplifying tasks such as making
* lex and yacc read from strings for mdb_eval(), and making our ELF file
* processing code read executable "files" from a crash dump via kvm_uread.
*
* Additionally, the formatting code provides auto-wrap and indent facilities
* that are necessary for compatibility with adb macro formatting. In auto-
* wrap mode, the formatting code examines each new chunk of output to determine
* if it will fit on the current line. If not, instead of having the chunk
* divided between the current line of output and the next, the auto-wrap
* code will automatically output a newline, auto-indent the next line,
* and then continue. Auto-indent is implemented by simply prepending a number
* of blanks equal to iob_margin to the start of each line. The margin is
* inserted when the iob is created, and following each flush of the buffer.
*/
#include <stdarg.h>
#include <mdb/mdb_types.h>
#include <mdb/mdb_argvec.h>
#include <mdb/mdb_stdlib.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_target.h>
#include <mdb/mdb_signal.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_io_impl.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_demangle.h>
#include <mdb/mdb_frame.h>
/*
* Define list of possible integer sizes for conversion routines:
*/
typedef enum {
} intsize_t;
/*
* The iob snprintf family of functions makes use of a special "sprintf
* buffer" i/o backend in order to provide the appropriate snprintf semantics.
* This structure is maintained as the backend-specific private storage,
* and its use is described in more detail below (see spbuf_write()).
*/
typedef struct {
} spbuf_t;
/*
* Define VA_ARG macro for grabbing the next datum to format for the printf
* family of functions. We use VA_ARG so that we can support two kinds of
* argument lists: the va_list type supplied by <stdarg.h> used for printf and
* vprintf, and an array of mdb_arg_t structures, which we expect will be
* either type STRING or IMMEDIATE. The vec_arg function takes care of
* handling the mdb_arg_t case.
*/
typedef enum {
} vatype_t;
typedef struct {
union {
} _val_u;
} varglist_t;
/*
* Define macro for converting char constant to Ctrl-char equivalent:
*/
#ifndef CTRL
#endif
/*
* Define macro for determining if we should automatically wrap to the next
* line of output, based on the amount of consumed buffer space and the
* specified size of the next thing to be inserted (n).
*/
/*
* Define prompt string and string to erase prompt string for iob_pager
* function, which is invoked if the pager is enabled on an i/o buffer
* and we're about to print a line which would be the last on the screen.
*/
static const char io_pbcksp[] =
/*CSTYLED*/
"\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";
static ssize_t
{
while (resid != 0) {
break;
}
/*
* Note that if we had a partial write before an error, we still want
* to return the fact something was written. The caller will get an
* error next time it tries to write anything.
*/
if (resid == n && n != 0) {
return (-1);
}
return (n - resid);
}
static ssize_t
{
switch (len) {
case -1:
break;
case 0:
break;
default:
}
return (len);
}
/*ARGSUSED*/
static void
{
}
static int
{
int status = 0;
uchar_t c;
void *termio_data;
return (0);
/*
* Reset the cursor back to column zero before printing a new
* prompt, since its position is unreliable after a SIGWINCH.
*/
/*
* If an existing SIGWINCH handler was present, call it. We
* expect that this will be termio: the handler will read the
* new window size, and then resize this iob appropriately.
*/
/*
* If the window has increased in size, we treat this like a
* request to fill out the new remainder of the page.
*/
status = 0;
goto winch;
}
}
for (;;) {
break;
}
switch (c) {
case 'N':
case 'n':
case '\n':
case '\r':
goto done;
case CTRL('c'):
case CTRL('\\'):
case 'Q':
case 'q':
goto done;
case 'A':
case 'a':
goto done;
case 'C':
case 'c':
/*FALLTHRU*/
case ' ':
goto done;
}
}
done:
return (status);
}
static void
{
size_t i;
for (i = 0; i < iob->iob_margin; i++)
}
}
static void
{
if (*p++ != ' ')
return;
}
iob->iob_nbytes = 0;
}
}
{
iob->iob_nbytes = 0;
iob->iob_nlines = 0;
return (iob);
}
void
{
int i;
for (i = 0; i < 2; i++) {
}
}
void
{
/*
* Don't flush a pipe, since it may cause a context swith when the
* other side has already been destroyed.
*/
if (!mdb_iob_isapipe(iob))
(void) mdb_iob_pop_io(iob);
}
}
void
{
iob->iob_nbytes = 0;
}
void
{
int pgerr = 0;
if (iob->iob_nbytes == 0)
return; /* Nothing to do if buffer is empty */
iob->iob_nlines = 0;
iob->iob_nlines = 0;
}
if (pgerr == 0) {
/*
* We only jump out of the dcmd on error if the iob is
* m_out. Presumably, if a dcmd has opened a special
* file and is writing to it, it will handle errors
* properly.
*/
iob->iob_nlines++;
}
}
iob->iob_nbytes = 0;
if (pgerr)
}
void
{
if (iob->iob_nbytes != 0)
else
}
void
{
}
mdb_io_t *
{
}
return (io);
}
void
{
else
}
void
{
}
}
void
{
}
void
{
}
void
{
}
void
{
iob->iob_nlines = 0;
}
void
{
if (flags & MDB_IOB_INDENT)
}
void
{
if (flags & MDB_IOB_INDENT)
}
{
}
static uintmax_t
{
else
(*app)++;
return (value);
}
static const char *
{
switch (size) {
case SZ_SHORT:
return ("short");
case SZ_INT:
return ("int");
case SZ_LONG:
return ("long");
case SZ_LONGLONG:
return ("long long");
}
return ("");
}
/*
* In order to simplify maintenance of the ::formats display, we provide an
* unparser for mdb_printf format strings that converts a simple format
* string with one specifier into a descriptive representation, e.g.
* mdb_iob_format2str("%llx") returns "hexadecimal long long".
*/
const char *
{
const char *p;
buf[0] = '\0';
goto done;
switch (*++p) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
while (*p >= '0' && *p <= '9')
p++;
p--;
goto fmt_switch;
case 'a':
case 'A':
return ("symbol");
case 'b':
break;
case 'c':
return ("character");
case 'd':
case 'i':
break;
case 'e':
case 'E':
case 'g':
case 'G':
return ("double");
case 'h':
goto fmt_switch;
case 'H':
return ("human-readable size");
case 'I':
return ("IPv4 address");
case 'l':
size = SZ_LONGLONG;
else
goto fmt_switch;
case 'm':
return ("margin");
case 'N':
return ("IPv6 address");
case 'o':
break;
case 'p':
return ("pointer");
case 'q':
break;
case 'r':
break;
case 'R':
break;
case 's':
return ("string");
case 't':
case 'T':
return ("tab");
case 'u':
break;
case 'x':
case 'X':
break;
case 'Y':
return ("time_t");
case '<':
return ("terminal attribute");
case '?':
case '#':
case '+':
case '-':
goto fmt_switch;
}
done:
if (buf[0] == '\0')
return ((const char *)buf);
}
static const char *
{
uintmax_t i;
switch (size) {
case SZ_LONGLONG:
if (flags & NTOS_UNSIGNED)
else
break;
case SZ_LONG:
if (flags & NTOS_UNSIGNED)
else
break;
case SZ_SHORT:
if (flags & NTOS_UNSIGNED)
else
break;
default:
if (flags & NTOS_UNSIGNED)
else
}
*zero = i == 0; /* Return flag indicating if result was zero */
*value = i; /* Return value retrieved from va_list */
}
static const char *
{
/*
* ctime(3c) returns a string of the form
* "Fri Sep 13 00:00:00 1986\n\0". We turn this into the canonical
* adb /y format "1986 Sep 13 00:00:00" below.
*/
int i;
for (i = 20; i < 24; i++)
for (i = 3; i < 19; i++)
*dst = '\0';
return (buf);
}
static const char *
{
return (NULL);
/*
* Here we provide a little cooperation between the %a formatting code
* and the proc target: if the initial address passed to %a is in fact
* a PLT address, the proc target's lookup_by_addr code will convert
* this to the PLT destination (a different address). We do not want
* to append a "+/-offset" suffix based on comparison with the query
* symbol in this case because the proc target has really done a hidden
* query for us with a different address. We detect this case by
* comparing the initial characters of buf to the special PLT= string.
*/
else
}
return (name);
}
/*
* Produce human-readable size, similar in spirit (and identical in output)
* to libzfs's zfs_nicenum() -- but made significantly more complicated by
* the constraint that we cannot use snprintf() as an implementation detail.
* Recall, floating point is verboten in kmdb.
*/
static const char *
{
#ifndef _KMDB
#endif
uint64_t n;
int index = 0;
char u;
switch (size) {
case SZ_LONGLONG:
break;
case SZ_LONG:
break;
case SZ_SHORT:
default:
}
#ifndef _KMDB
orig = n;
#endif
while (n >= 1024) {
n /= 1024;
index++;
}
u = " KMGTPE"[index];
buf[0] = '\0';
if (index == 0) {
return (numtostr(n, 10, 0));
#ifndef _KMDB
#else
} else {
#endif
/*
* If this is an even multiple of the base or we are in an
* environment where floating point is verboten (i.e., kmdb),
* always display without any decimal precision.
*/
#ifndef _KMDB
} else {
/*
* We want to choose a precision that results in the specified
* number of significant figures (by default, 3). This is
* similar to the output that one would get specifying the %.*g
* format specifier (where the asterisk denotes the number of
* significant digits), but (1) we include trailing zeros if
* the there are non-zero digits beyond the number of
* significant digits (that is, 10241 is '10.0K', not the
* '10K' that it would be with %.3g) and (2) we never resort
* to %e notation when the number of digits exceeds the
* number of significant figures (that is, 1043968 is '1020K',
* not '1.02e+03K'). This is also made somewhat complicated
* by the fact that we need to deal with rounding (10239 is
* '10.0K', not '9.99K'), for which we perform nearest-even
* rounding.
*/
for (i = 0; i < sigfig - 1; i++)
mag *= 10;
uint32_t v;
/*
* Note that we cast mult to a 32-bit value. We know
* that val is less than 1024 due to the logic above,
* and that mag is at most 10^(sigfig - 1). This means
* that as long as sigfig is 9 or lower, this will not
* overflow. (We perform this cast because it assures
* that we are never converting a double to a uint64_t,
* which for some compilers requires a call to a
* function not guaranteed to be in libstand.)
*/
} else {
/*
* We are exactly between integer multiples
* of units; perform nearest-even rounding
* to be consistent with the behavior of
* printf().
*/
v++;
}
if (mag == 1) {
break;
}
if (v < thresh) {
i -= strlen(c);
/*
* We need to zero-fill from the right of the
* decimal point to the first significant digit
* of the fractional component.
*/
while (i--)
break;
}
}
#endif
}
*c++ = u;
*c++ = '\0';
return (buf);
}
static int
{
int req;
if (nbytes != 0 && *s == '/') {
nbytes--;
s++;
} else
if (nbytes != 1)
switch (*s) {
case 's':
attr = ATT_STANDOUT;
break;
case 'u':
break;
case 'r':
attr = ATT_REVERSE;
break;
case 'b':
break;
case 'd':
break;
case 'a':
break;
default:
}
/*
* We need to flush the current buffer contents before calling
* IOP_SETATTR because IOP_SETATTR may need to synchronously output
* terminal escape sequences directly to the underlying device.
*/
iob->iob_nbytes = 0;
}
static void
{
const char *str;
goto out;
if (delim)
else
}
}
out:
if (delim)
}
}
static const char *
{
return (buf);
}
static const char *
{
return (buf);
}
static const char *
{
char *var;
if (len == 0) {
return (NULL);
}
return (NULL);
}
}
/*
* The iob_doprnt function forms the main engine of the debugger's output
* formatting capabilities. Note that this is NOT exactly compatible with
* the printf(3S) family, nor is it intended to be so. We support some
* extensions and format characters not supported by printf(3S), and we
* explicitly do NOT provide support for %C, %S, %ws (wide-character strings),
* do NOT provide for the complete functionality of %f, %e, %E, %g, %G
* (alternate double formats), and do NOT support %.x (precision specification).
* Note that iob_doprnt consumes varargs off the original va_list.
*/
static void
{
char c[2] = { 0, 0 }; /* Buffer for single character output */
const char *p; /* Current position in format string */
union {
const char *str;
void *ptr;
char c;
double d;
long double ld;
} u;
/*
* Output the format string verbatim up to the next '%' char
*/
if (p != format) {
}
/*
* Now we need to parse the sequence of format characters
* following the % marker and do the appropriate thing.
*/
flags = 0; /* Clear numtostr() format flags */
width = 0; /* No field width limit by default */
altlen = 0; /* No alternate format string yet */
switch (*++p) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
goto fmt_switch;
}
width = 0; /* clear any other width specifier */
for (u.c = *p; u.c >= '0' && u.c <= '9'; u.c = *++p)
p--;
goto fmt_switch;
case 'a':
altstr = ":";
altlen = 1;
}
break;
case 'A':
u.str = "?";
break;
case 'b':
format = ++p;
continue;
case 'c':
u.str = c;
break;
case 'd':
case 'i':
if (f_alt)
flags |= NTOS_SHOWBASE;
break;
/* No floating point in kmdb */
#ifndef _KMDB
case 'e':
case 'E':
break;
case 'g':
case 'G':
(*p == 'g') ? 'e' : 'E');
} else {
(*p == 'g') ? 'e' : 'E');
}
break;
#endif
case 'h':
goto fmt_switch;
case 'H':
break;
case 'I':
break;
case 'l':
size = SZ_LONGLONG;
else
goto fmt_switch;
case 'm':
if (iob->iob_nbytes == 0) {
iob->iob_margin);
}
format = ++p;
continue;
case 'N':
break;
case 'o':
altstr = "0";
altlen = 1;
}
break;
case 'p':
break;
case 'q':
altstr = "0";
altlen = 1;
}
break;
case 'r':
if (f_alt)
flags |= NTOS_SHOWBASE;
break;
case 'R':
if (f_alt)
flags |= NTOS_SHOWBASE;
break;
case 's':
break;
case 't':
if (width != 0) {
while (width-- > 0)
} else
format = ++p;
continue;
case 'T':
}
format = ++p;
continue;
case 'u':
if (f_alt)
flags |= NTOS_SHOWBASE;
break;
case 'x':
altstr = "0x";
altlen = 2;
}
break;
case 'X':
altstr = "0X";
altlen = 2;
}
break;
case 'Y':
break;
case '<':
/*
* Used to turn attributes on (<b>), to turn them
* off (</b>), or to print variables (<_var>).
*/
continue;
if (*p == '>') {
if (paramlen > 0) {
if (*u.str == '_') {
paramlen - 1);
break;
} else {
paramlen);
}
}
p++;
}
format = p;
continue;
case '*':
goto fmt_switch;
case '%':
u.str = "%";
break;
case '?':
goto fmt_switch;
case '#':
goto fmt_switch;
case '+':
flags |= NTOS_SIGNPOS;
goto fmt_switch;
case '-':
goto fmt_switch;
default:
c[0] = p[0];
u.str = c;
}
/*
* If the string and the option altstr won't fit on this line
* and auto-wrap is set (default), skip to the next line.
* If the string contains \n, and the \n terminated substring
* + altstr is shorter than the above, use the shorter lf_len.
*/
}
}
/*
* Optionally add whitespace or zeroes prefixing the value if
* we haven't filled the minimum width and we're right-aligned.
*/
}
/*
* Print the alternate string if it's a prefix, and then
* print the value string itself.
*/
if (len != 0)
/*
* If we have an alternate string and it's a suffix, print it.
*/
/*
* Finally, if we haven't filled the field width and we're
* left-aligned, pad out the rest with whitespace.
*/
format = (*p != '\0') ? ++p : p;
}
/*
* If there's anything left in the format string, output it now
*/
if (*format != '\0') {
}
}
void
{
}
void
{
}
void
{
}
/*
* In order to handle the sprintf family of functions, we define a special
* i/o backend known as a "sprintf buf" (or spbuf for short). This back end
* provides an IOP_WRITE entry point that concatenates each buffer sent from
* mdb_iob_flush() onto the caller's buffer until the caller's buffer is
* exhausted. We also keep an absolute count of how many bytes were sent to
* this function during the lifetime of the snprintf call. This allows us
* to provide the ability to (1) return the total size required for the given
* format string and argument list, and (2) support a call to snprintf with a
* NULL buffer argument with no special case code elsewhere.
*/
static ssize_t
{
if (spb->spb_bufsiz != 0) {
spb->spb_bufsiz -= n;
}
return (buflen);
}
};
/*
* The iob_spb_create function initializes an iob suitable for snprintf calls,
* a spbuf i/o backend, and the spbuf private data, and then glues these
* objects together. The caller (either vsnprintf or asnprintf below) is
* expected to have allocated the various structures on their stack.
*/
static void
{
iob->iob_nbytes = 0;
iob->iob_nlines = 0;
}
/*ARGSUSED*/
{
return (nbytes);
}
};
mdb_io_t *
mdb_nullio_create(void)
{
&null_ops,
NULL,
NULL,
1
};
return (&null_io);
}
{
mdb_iob_flush(&iob);
if (spb.spb_bufsiz != 0)
}
{
mdb_iob_flush(&iob);
if (spb.spb_bufsiz != 0)
}
/*PRINTFLIKE3*/
{
return (nbytes);
}
void
{
const char *p, *q = s;
if (nbytes == 0)
return; /* Return immediately if there is no work to do */
/*
* If the string contains embedded newlines or tabs, invoke ourself
* recursively for each string component, followed by a call to the
* newline or tab routine. This insures that strings with these
* characters obey our wrapping and indenting rules, and that strings
* with embedded newlines are flushed after each newline, allowing
* the output pager to take over if it is enabled.
*/
if (p > q)
if (*p == '\t')
else
q = p + 1; /* Advance past delimiter */
}
/*
* For a given string component, we determine how many bytes (n) we can
* copy into our buffer (limited by either cols or bufsiz depending
* on whether AUTOWRAP is on), copy a chunk into the buffer, and
* flush the buffer if we reach the end of a line.
*/
while (nleft != 0) {
} else {
}
nleft -= m;
q += m;
iob->iob_nbytes += m;
if (m == n && nleft != 0) {
else
}
}
}
void
{
}
void
{
}
void
{
if (iob->iob_tabstop != 0) {
/*
* Round up to the next multiple of the tabstop. If this puts
* us off the end of the line, just insert a newline; otherwise
* insert sufficient whitespace to reach position n.
*/
else
}
}
void
{
size_t i, m, n;
while (nfill != 0) {
} else {
}
for (i = 0; i < m; i++)
iob->iob_nbytes += m;
nfill -= m;
if (m == n && nfill != 0) {
else
}
}
}
void
{
else
}
void
{
iob->iob_nbytes++;
}
{
int c;
return (EOF); /* can't gets a write buf or a read buf at EOF */
if (n == 0)
return (0); /* we need room for a terminating \0 */
while (resid != 0) {
goto done; /* failed to refill buffer */
iob->iob_nbytes--;
if (c == EOF || c == '\n')
goto done;
*buf++ = (char)c;
resid--;
}
}
done:
*buf = '\0';
return (n - resid - 1);
}
int
{
int c;
return (EOF); /* can't getc if write-only, EOF, or error bit */
return (EOF); /* failed to refill buffer */
iob->iob_nbytes--;
return (c);
}
int
{
return (EOF); /* can't ungetc if write-only or error bit set */
return (EOF); /* can't ungetc EOF, or ungetc if buffer full */
iob->iob_nbytes++;
return (c);
}
int
{
(MDB_IOB_RDONLY | MDB_IOB_EOF));
}
int
{
}
{
return (0); /* can't read if write-only, eof, or error */
while (resid != 0) {
break; /* failed to refill buffer */
}
return (n - resid);
}
/*
* For now, all binary writes are performed unbuffered. This has the
* side effect that the pager will not be triggered by mdb_iob_write.
*/
{
return (ret);
}
int
{
}
const char *
{
return ("<NULL>");
}
{
return (iob->iob_lineno);
}
{
return (iob->iob_tabstop);
}
{
return (iob->iob_margin);
}
mdb_io_t *
{
return (io);
}
void
{
}
}
void
{
}
void
{
}
void
{
}
}
void
{
yylineno = 1;
}
{
return (top);
}
{
}
/*
* Stub functions for i/o backend implementors: these stubs either act as
* pass-through no-ops or return ENOTSUP as appropriate.
*/
{
}
{
}
{
}
int
{
}
/*ARGSUSED*/
void
{
/*
* Note that we do not propagate IOP_CLOSE down the io stack. IOP_CLOSE should
* only be called by mdb_io_rele when an io's reference count has gone to zero.
*/
}
const char *
{
return ("(anonymous)");
}
void
{
}
void
{
}
int
{
}
void
{
}
void
{
}
/*
* Iterate over the varargs. The first item indicates the mode:
* MDB_TBL_PRNT
* pull out the next vararg as a const char * and pass it and the
* remaining varargs to iob_doprnt; if we want to print the column,
* direct the output to mdb.m_out otherwise direct it to mdb.m_null
*
* MDB_TBL_FUNC
* pull out the next vararg as type mdb_table_print_f and the
* following one as a void * argument to the function; call the
* function with the given argument if we want to print the column
*
* The second item indicates the flag; if the flag is set in the flags
* argument, then the column is printed. A flag value of 0 indicates
* that the column should always be printed.
*/
void
{
const char *fmt;
void *arg;
if (print) {
if (first)
else
}
switch (type) {
case MDB_TBL_PRNT: {
break;
}
case MDB_TBL_FUNC:
if (print)
break;
default:
break;
}
}
}