Home | History | Annotate | Download | only in mdb
      1      0   stevel /*
      2      0   stevel  * CDDL HEADER START
      3      0   stevel  *
      4      0   stevel  * The contents of this file are subject to the terms of the
      5   3277       af  * Common Development and Distribution License (the "License").
      6   3277       af  * You may not use this file except in compliance with the License.
      7      0   stevel  *
      8      0   stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0   stevel  * or http://www.opensolaris.org/os/licensing.
     10      0   stevel  * See the License for the specific language governing permissions
     11      0   stevel  * and limitations under the License.
     12      0   stevel  *
     13      0   stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0   stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0   stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0   stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0   stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0   stevel  *
     19      0   stevel  * CDDL HEADER END
     20      0   stevel  */
     21      0   stevel /*
     22  11053    Surya  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0   stevel  * Use is subject to license terms.
     24      0   stevel  */
     25      0   stevel 
     26      0   stevel /*
     27      0   stevel  * Modular Debugger (MDB)
     28      0   stevel  *
     29      0   stevel  * Refer to the white paper "A Modular Debugger for Solaris" for information
     30      0   stevel  * on the design, features, and goals of MDB.  See /shared/sac/PSARC/1999/169
     31      0   stevel  * for copies of the paper and related documentation.
     32      0   stevel  *
     33      0   stevel  * This file provides the basic construction and destruction of the debugger's
     34      0   stevel  * global state, as well as the main execution loop, mdb_run().  MDB maintains
     35      0   stevel  * a stack of execution frames (mdb_frame_t's) that keep track of its current
     36      0   stevel  * state, including a stack of input and output buffers, walk and memory
     37      0   stevel  * garbage collect lists, and a list of commands (mdb_cmd_t's).  As the
     38      0   stevel  * parser consumes input, it fills in a list of commands to execute, and then
     39      0   stevel  * invokes mdb_call(), below.  A command consists of a dcmd, telling us
     40      0   stevel  * what function to execute, and a list of arguments and other invocation-
     41      0   stevel  * specific data.  Each frame may have more than one command, kept on a list,
     42      0   stevel  * when multiple commands are separated by | operators.  New frames may be
     43      0   stevel  * stacked on old ones by nested calls to mdb_run: this occurs when, for
     44      0   stevel  * example, in the middle of processing one input source (such as a file
     45      0   stevel  * or the terminal), we invoke a dcmd that in turn calls mdb_eval().  mdb_eval
     46      0   stevel  * will construct a new frame whose input source is the string passed to
     47      0   stevel  * the eval function, and then execute this frame to completion.
     48      0   stevel  */
     49      0   stevel 
     50      0   stevel #include <sys/param.h>
     51      0   stevel #include <stropts.h>
     52      0   stevel 
     53      0   stevel #define	_MDB_PRIVATE
     54      0   stevel #include <mdb/mdb.h>
     55      0   stevel 
     56      0   stevel #include <mdb/mdb_context.h>
     57      0   stevel #include <mdb/mdb_argvec.h>
     58      0   stevel #include <mdb/mdb_signal.h>
     59      0   stevel #include <mdb/mdb_macalias.h>
     60      0   stevel #include <mdb/mdb_module.h>
     61      0   stevel #include <mdb/mdb_modapi.h>
     62      0   stevel #include <mdb/mdb_string.h>
     63      0   stevel #include <mdb/mdb_callb.h>
     64      0   stevel #include <mdb/mdb_debug.h>
     65      0   stevel #include <mdb/mdb_frame.h>
     66      0   stevel #include <mdb/mdb_conf.h>
     67      0   stevel #include <mdb/mdb_err.h>
     68      0   stevel #include <mdb/mdb_lex.h>
     69      0   stevel #include <mdb/mdb_io.h>
     70      0   stevel #ifdef _KMDB
     71      0   stevel #include <kmdb/kmdb_module.h>
     72      0   stevel #endif
     73      0   stevel 
     74      0   stevel /*
     75      0   stevel  * Macro for testing if a dcmd's return status (x) indicates that we should
     76      0   stevel  * abort the current loop or pipeline.
     77      0   stevel  */
     78      0   stevel #define	DCMD_ABORTED(x)	((x) == DCMD_USAGE || (x) == DCMD_ABORT)
     79      0   stevel 
     80      0   stevel extern const mdb_dcmd_t mdb_dcmd_builtins[];
     81      0   stevel extern mdb_dis_ctor_f *const mdb_dis_builtins[];
     82      0   stevel 
     83      0   stevel /*
     84      0   stevel  * Variable discipline for toggling MDB_FL_PSYM based on the value of the
     85      0   stevel  * undocumented '_' variable.  Once adb(1) has been removed from the system,
     86      0   stevel  * we should just remove this functionality and always disable PSYM for macros.
     87      0   stevel  */
     88      0   stevel static uintmax_t
     89      0   stevel psym_disc_get(const mdb_var_t *v)
     90      0   stevel {
     91      0   stevel 	int i = (mdb.m_flags & MDB_FL_PSYM) ? 1 : 0;
     92      0   stevel 	int j = (MDB_NV_VALUE(v) != 0) ? 1 : 0;
     93      0   stevel 
     94      0   stevel 	if ((i ^ j) == 0)
     95      0   stevel 		MDB_NV_VALUE((mdb_var_t *)v) = j ^ 1;
     96      0   stevel 
     97      0   stevel 	return (MDB_NV_VALUE(v));
     98      0   stevel }
     99      0   stevel 
    100      0   stevel static void
    101      0   stevel psym_disc_set(mdb_var_t *v, uintmax_t value)
    102      0   stevel {
    103      0   stevel 	if (value == 0)
    104      0   stevel 		mdb.m_flags |= MDB_FL_PSYM;
    105      0   stevel 	else
    106      0   stevel 		mdb.m_flags &= ~MDB_FL_PSYM;
    107      0   stevel 
    108      0   stevel 	MDB_NV_VALUE(v) = value;
    109      0   stevel }
    110      0   stevel 
    111      0   stevel /*
    112      0   stevel  * Variable discipline for making <1 (most recent offset) behave properly.
    113      0   stevel  */
    114      0   stevel static uintmax_t
    115      0   stevel roff_disc_get(const mdb_var_t *v)
    116      0   stevel {
    117      0   stevel 	return (MDB_NV_VALUE(v));
    118      0   stevel }
    119      0   stevel 
    120      0   stevel static void
    121      0   stevel roff_disc_set(mdb_var_t *v, uintmax_t value)
    122      0   stevel {
    123      0   stevel 	mdb_nv_set_value(mdb.m_proffset, MDB_NV_VALUE(v));
    124      0   stevel 	MDB_NV_VALUE(v) = value;
    125      0   stevel }
    126      0   stevel 
    127      0   stevel /*
    128      0   stevel  * Variable discipline for exporting the representative thread.
    129      0   stevel  */
    130      0   stevel static uintmax_t
    131      0   stevel thr_disc_get(const mdb_var_t *v)
    132      0   stevel {
    133      0   stevel 	mdb_tgt_status_t s;
    134      0   stevel 
    135      0   stevel 	if (mdb.m_target != NULL && mdb_tgt_status(mdb.m_target, &s) == 0)
    136      0   stevel 		return (s.st_tid);
    137      0   stevel 
    138      0   stevel 	return (MDB_NV_VALUE(v));
    139      0   stevel }
    140      0   stevel 
    141      0   stevel const char **
    142      0   stevel mdb_path_alloc(const char *s, size_t *newlen)
    143      0   stevel {
    144      0   stevel 	char *format = mdb_alloc(strlen(s) * 2 + 1, UM_NOSLEEP);
    145      0   stevel 	const char **path;
    146      0   stevel 	char *p, *q;
    147      0   stevel 
    148      0   stevel 	struct utsname uts;
    149      0   stevel 	size_t len;
    150      0   stevel 	int i;
    151      0   stevel 
    152      0   stevel 	mdb_arg_t arg_i, arg_m, arg_p, arg_r, arg_t, arg_R, arg_V;
    153      0   stevel 	mdb_argvec_t argv;
    154      0   stevel 
    155      0   stevel 	static const char *empty_path[] = { NULL };
    156      0   stevel 
    157      0   stevel 	if (format == NULL)
    158      0   stevel 		goto nomem;
    159      0   stevel 
    160      0   stevel 	while (*s == ':')
    161      0   stevel 		s++; /* strip leading delimiters */
    162      0   stevel 
    163      0   stevel 	if (*s == '\0') {
    164      0   stevel 		*newlen = 0;
    165      0   stevel 		return (empty_path);
    166      0   stevel 	}
    167      0   stevel 
    168      0   stevel 	(void) strcpy(format, s);
    169      0   stevel 	mdb_argvec_create(&argv);
    170      0   stevel 
    171      0   stevel 	/*
    172      0   stevel 	 * %i embedded in path string expands to ISA.
    173      0   stevel 	 */
    174      0   stevel 	arg_i.a_type = MDB_TYPE_STRING;
    175      0   stevel 	if (mdb.m_target != NULL)
    176      0   stevel 		arg_i.a_un.a_str = mdb_tgt_isa(mdb.m_target);
    177      0   stevel 	else
    178      0   stevel 		arg_i.a_un.a_str = mdb_conf_isa();
    179      0   stevel 
    180      0   stevel 	/*
    181      0   stevel 	 * %p embedded in path string expands to the platform name.
    182      0   stevel 	 */
    183      0   stevel 	arg_p.a_type = MDB_TYPE_STRING;
    184      0   stevel 	if (mdb.m_target != NULL)
    185      0   stevel 		arg_p.a_un.a_str = mdb_tgt_platform(mdb.m_target);
    186      0   stevel 	else
    187      0   stevel 		arg_p.a_un.a_str = mdb_conf_platform();
    188      0   stevel 
    189      0   stevel 	/*
    190      0   stevel 	 * %r embedded in path string expands to root directory, or
    191      0   stevel 	 * to the empty string if root is "/" (to avoid // in paths).
    192      0   stevel 	 */
    193      0   stevel 	arg_r.a_type = MDB_TYPE_STRING;
    194      0   stevel 	arg_r.a_un.a_str = strcmp(mdb.m_root, "/") ? mdb.m_root : "";
    195      0   stevel 
    196      0   stevel 	/*
    197   5084  johnlev 	 * %t embedded in path string expands to the target name, defaulting to
    198   5084  johnlev 	 * kvm; this is so we can find mdb_kb, which is used during bootstrap.
    199      0   stevel 	 */
    200      0   stevel 	arg_t.a_type = MDB_TYPE_STRING;
    201   5084  johnlev 	arg_t.a_un.a_str = mdb.m_target ? mdb_tgt_name(mdb.m_target) : "kvm";
    202      0   stevel 
    203      0   stevel 	/*
    204      0   stevel 	 * %R and %V expand to uname -r (release) and uname -v (version).
    205      0   stevel 	 */
    206      0   stevel 	if (mdb.m_target == NULL || mdb_tgt_uname(mdb.m_target, &uts) < 0)
    207      0   stevel 		mdb_conf_uname(&uts);
    208      0   stevel 
    209      0   stevel 	arg_m.a_type = MDB_TYPE_STRING;
    210      0   stevel 	arg_m.a_un.a_str = uts.machine;
    211      0   stevel 
    212      0   stevel 	arg_R.a_type = MDB_TYPE_STRING;
    213      0   stevel 	arg_R.a_un.a_str = uts.release;
    214      0   stevel 
    215      0   stevel 	arg_V.a_type = MDB_TYPE_STRING;
    216      0   stevel 	if (mdb.m_flags & MDB_FL_LATEST)
    217      0   stevel 		arg_V.a_un.a_str = "latest";
    218      0   stevel 	else
    219      0   stevel 		arg_V.a_un.a_str = uts.version;
    220      0   stevel 
    221      0   stevel 	/*
    222      0   stevel 	 * In order to expand the buffer, we examine the format string for
    223      0   stevel 	 * our % tokens and construct an argvec, replacing each % token
    224      0   stevel 	 * with %s along the way.  If we encounter an unknown token, we
    225      0   stevel 	 * shift over the remaining format buffer and stick in %%.
    226      0   stevel 	 */
    227      0   stevel 	for (q = format; (q = strchr(q, '%')) != NULL; q++) {
    228      0   stevel 		switch (q[1]) {
    229      0   stevel 		case 'i':
    230      0   stevel 			mdb_argvec_append(&argv, &arg_i);
    231      0   stevel 			*++q = 's';
    232      0   stevel 			break;
    233      0   stevel 		case 'm':
    234      0   stevel 			mdb_argvec_append(&argv, &arg_m);
    235      0   stevel 			*++q = 's';
    236      0   stevel 			break;
    237      0   stevel 		case 'p':
    238      0   stevel 			mdb_argvec_append(&argv, &arg_p);
    239      0   stevel 			*++q = 's';
    240      0   stevel 			break;
    241      0   stevel 		case 'r':
    242      0   stevel 			mdb_argvec_append(&argv, &arg_r);
    243      0   stevel 			*++q = 's';
    244      0   stevel 			break;
    245      0   stevel 		case 't':
    246      0   stevel 			mdb_argvec_append(&argv, &arg_t);
    247      0   stevel 			*++q = 's';
    248      0   stevel 			break;
    249      0   stevel 		case 'R':
    250      0   stevel 			mdb_argvec_append(&argv, &arg_R);
    251      0   stevel 			*++q = 's';
    252      0   stevel 			break;
    253      0   stevel 		case 'V':
    254      0   stevel 			mdb_argvec_append(&argv, &arg_V);
    255      0   stevel 			*++q = 's';
    256      0   stevel 			break;
    257      0   stevel 		default:
    258      0   stevel 			bcopy(q + 1, q + 2, strlen(q));
    259      0   stevel 			*++q = '%';
    260      0   stevel 		}
    261      0   stevel 	}
    262      0   stevel 
    263      0   stevel 	/*
    264      0   stevel 	 * We're now ready to use our printf engine to format the final string.
    265      0   stevel 	 * Take one lap with a NULL buffer to determine how long the final
    266      0   stevel 	 * string will be, allocate it, and format it.
    267      0   stevel 	 */
    268      0   stevel 	len = mdb_iob_asnprintf(NULL, 0, format, argv.a_data);
    269      0   stevel 	if ((p = mdb_alloc(len + 1, UM_NOSLEEP)) != NULL)
    270      0   stevel 		(void) mdb_iob_asnprintf(p, len + 1, format, argv.a_data);
    271      0   stevel 	else
    272      0   stevel 		goto nomem;
    273      0   stevel 
    274      0   stevel 	mdb_argvec_zero(&argv);
    275      0   stevel 	mdb_argvec_destroy(&argv);
    276      0   stevel 
    277      0   stevel 	mdb_free(format, strlen(s) * 2 + 1);
    278      0   stevel 	format = NULL;
    279      0   stevel 
    280      0   stevel 	/*
    281      0   stevel 	 * Compress the string to exclude any leading delimiters.
    282      0   stevel 	 */
    283      0   stevel 	for (q = p; *q == ':'; q++)
    284      0   stevel 		continue;
    285      0   stevel 	if (q != p)
    286      0   stevel 		bcopy(q, p, strlen(q) + 1);
    287      0   stevel 
    288      0   stevel 	/*
    289      0   stevel 	 * Count up the number of delimited elements.  A sequence of
    290      0   stevel 	 * consecutive delimiters is only counted once.
    291      0   stevel 	 */
    292      0   stevel 	for (i = 1, q = p; (q = strchr(q, ':')) != NULL; i++) {
    293      0   stevel 		while (*q == ':')
    294      0   stevel 			q++;
    295      0   stevel 	}
    296      0   stevel 
    297      0   stevel 	if ((path = mdb_alloc(sizeof (char *) * (i + 1), UM_NOSLEEP)) == NULL) {
    298      0   stevel 		mdb_free(p, len + 1);
    299      0   stevel 		goto nomem;
    300      0   stevel 	}
    301      0   stevel 
    302      0   stevel 	for (i = 0, q = strtok(p, ":"); q != NULL; q = strtok(NULL, ":"))
    303      0   stevel 		path[i++] = q;
    304      0   stevel 
    305      0   stevel 	path[i] = NULL;
    306      0   stevel 	*newlen = len + 1;
    307      0   stevel 	return (path);
    308      0   stevel 
    309      0   stevel nomem:
    310      0   stevel 	warn("failed to allocate memory for path");
    311      0   stevel 	if (format != NULL)
    312      0   stevel 		mdb_free(format, strlen(s) * 2 + 1);
    313      0   stevel 	*newlen = 0;
    314      0   stevel 	return (empty_path);
    315      0   stevel }
    316      0   stevel 
    317      0   stevel const char **
    318      0   stevel mdb_path_dup(const char *path[], size_t pathlen, size_t *npathlenp)
    319      0   stevel {
    320      0   stevel 	char **npath;
    321      0   stevel 	int i, j;
    322      0   stevel 
    323      0   stevel 	for (i = 0; path[i] != NULL; i++)
    324      0   stevel 		continue; /* count the path elements */
    325      0   stevel 
    326      0   stevel 	npath = mdb_zalloc(sizeof (char *) * (i + 1), UM_SLEEP);
    327      0   stevel 	if (pathlen > 0) {
    328      0   stevel 		npath[0] = mdb_alloc(pathlen, UM_SLEEP);
    329      0   stevel 		bcopy(path[0], npath[0], pathlen);
    330      0   stevel 	}
    331      0   stevel 
    332      0   stevel 	for (j = 1; j < i; j++)
    333      0   stevel 		npath[j] = npath[0] + (path[j] - path[0]);
    334      0   stevel 	npath[i] = NULL;
    335      0   stevel 
    336      0   stevel 	*npathlenp = pathlen;
    337      0   stevel 	return ((const char **)npath);
    338      0   stevel }
    339      0   stevel 
    340      0   stevel void
    341      0   stevel mdb_path_free(const char *path[], size_t pathlen)
    342      0   stevel {
    343      0   stevel 	int i;
    344      0   stevel 
    345      0   stevel 	for (i = 0; path[i] != NULL; i++)
    346      0   stevel 		continue; /* count the path elements */
    347      0   stevel 
    348      0   stevel 	if (i > 0) {
    349      0   stevel 		mdb_free((void *)path[0], pathlen);
    350      0   stevel 		mdb_free(path, sizeof (char *) * (i + 1));
    351      0   stevel 	}
    352      0   stevel }
    353      0   stevel 
    354      0   stevel /*
    355      0   stevel  * Convert path string "s" to canonical form, expanding any %o tokens that are
    356      0   stevel  * found within the path.  The old path string is specified by "path", a buffer
    357      0   stevel  * of size MAXPATHLEN which is then overwritten with the new path string.
    358      0   stevel  */
    359      0   stevel static const char *
    360      0   stevel path_canon(char *path, const char *s)
    361      0   stevel {
    362      0   stevel 	char *p = path;
    363      0   stevel 	char *q = p + MAXPATHLEN - 1;
    364      0   stevel 
    365      0   stevel 	char old[MAXPATHLEN];
    366      0   stevel 	char c;
    367      0   stevel 
    368      0   stevel 	(void) strcpy(old, p);
    369      0   stevel 	*q = '\0';
    370      0   stevel 
    371      0   stevel 	while (p < q && (c = *s++) != '\0') {
    372      0   stevel 		if (c == '%') {
    373      0   stevel 			if ((c = *s++) == 'o') {
    374      0   stevel 				(void) strncpy(p, old, (size_t)(q - p));
    375      0   stevel 				p += strlen(p);
    376      0   stevel 			} else {
    377      0   stevel 				*p++ = '%';
    378      0   stevel 				if (p < q && c != '\0')
    379      0   stevel 					*p++ = c;
    380      0   stevel 				else
    381      0   stevel 					break;
    382      0   stevel 			}
    383      0   stevel 		} else
    384      0   stevel 			*p++ = c;
    385      0   stevel 	}
    386      0   stevel 
    387      0   stevel 	*p = '\0';
    388      0   stevel 	return (path);
    389      0   stevel }
    390      0   stevel 
    391      0   stevel void
    392      0   stevel mdb_set_ipath(const char *path)
    393      0   stevel {
    394      0   stevel 	if (mdb.m_ipath != NULL)
    395      0   stevel 		mdb_path_free(mdb.m_ipath, mdb.m_ipathlen);
    396      0   stevel 
    397      0   stevel 	path = path_canon(mdb.m_ipathstr, path);
    398      0   stevel 	mdb.m_ipath = mdb_path_alloc(path, &mdb.m_ipathlen);
    399      0   stevel }
    400      0   stevel 
    401      0   stevel void
    402      0   stevel mdb_set_lpath(const char *path)
    403      0   stevel {
    404      0   stevel 	if (mdb.m_lpath != NULL)
    405      0   stevel 		mdb_path_free(mdb.m_lpath, mdb.m_lpathlen);
    406      0   stevel 
    407      0   stevel 	path = path_canon(mdb.m_lpathstr, path);
    408      0   stevel 	mdb.m_lpath = mdb_path_alloc(path, &mdb.m_lpathlen);
    409      0   stevel 
    410      0   stevel #ifdef _KMDB
    411      0   stevel 	kmdb_module_path_set(mdb.m_lpath, mdb.m_lpathlen);
    412      0   stevel #endif
    413      0   stevel }
    414      0   stevel 
    415      0   stevel static void
    416      0   stevel prompt_update(void)
    417      0   stevel {
    418      0   stevel 	(void) mdb_snprintf(mdb.m_prompt, sizeof (mdb.m_prompt),
    419      0   stevel 	    mdb.m_promptraw);
    420      0   stevel 	mdb.m_promptlen = strlen(mdb.m_prompt);
    421      0   stevel }
    422      0   stevel 
    423      0   stevel const char *
    424      0   stevel mdb_get_prompt(void)
    425      0   stevel {
    426      0   stevel 	if (mdb.m_promptlen == 0)
    427      0   stevel 		return (NULL);
    428      0   stevel 	else
    429      0   stevel 		return (mdb.m_prompt);
    430      0   stevel }
    431      0   stevel 
    432      0   stevel int
    433      0   stevel mdb_set_prompt(const char *p)
    434      0   stevel {
    435      0   stevel 	size_t len = strlen(p);
    436      0   stevel 
    437      0   stevel 	if (len > MDB_PROMPTLEN) {
    438      0   stevel 		warn("prompt may not exceed %d characters\n", MDB_PROMPTLEN);
    439      0   stevel 		return (0);
    440      0   stevel 	}
    441      0   stevel 
    442      0   stevel 	(void) strcpy(mdb.m_promptraw, p);
    443      0   stevel 	prompt_update();
    444      0   stevel 	return (1);
    445      0   stevel }
    446      0   stevel 
    447      0   stevel static mdb_frame_t frame0;
    448      0   stevel 
    449      0   stevel void
    450      0   stevel mdb_create(const char *execname, const char *arg0)
    451      0   stevel {
    452      0   stevel 	static const mdb_nv_disc_t psym_disc = { psym_disc_set, psym_disc_get };
    453      0   stevel 	static const mdb_nv_disc_t roff_disc = { roff_disc_set, roff_disc_get };
    454      0   stevel 	static const mdb_nv_disc_t thr_disc = { NULL, thr_disc_get };
    455      0   stevel 
    456      0   stevel 	static char rootdir[MAXPATHLEN];
    457      0   stevel 
    458      0   stevel 	const mdb_dcmd_t *dcp;
    459      0   stevel 	int i;
    460      0   stevel 
    461      0   stevel 	bzero(&mdb, sizeof (mdb_t));
    462      0   stevel 
    463      0   stevel 	mdb.m_flags = MDB_FL_PSYM | MDB_FL_PAGER | MDB_FL_BPTNOSYMSTOP |
    464      0   stevel 	    MDB_FL_READBACK;
    465      0   stevel 	mdb.m_radix = MDB_DEF_RADIX;
    466      0   stevel 	mdb.m_nargs = MDB_DEF_NARGS;
    467      0   stevel 	mdb.m_histlen = MDB_DEF_HISTLEN;
    468      0   stevel 	mdb.m_armemlim = MDB_DEF_ARRMEM;
    469      0   stevel 	mdb.m_arstrlim = MDB_DEF_ARRSTR;
    470      0   stevel 
    471      0   stevel 	mdb.m_pname = strbasename(arg0);
    472      0   stevel 	if (strcmp(mdb.m_pname, "adb") == 0) {
    473      0   stevel 		mdb.m_flags |= MDB_FL_NOMODS | MDB_FL_ADB | MDB_FL_REPLAST;
    474      0   stevel 		mdb.m_flags &= ~MDB_FL_PAGER;
    475      0   stevel 	}
    476      0   stevel 
    477      0   stevel 	mdb.m_ipathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);
    478      0   stevel 	mdb.m_lpathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);
    479      0   stevel 
    480      0   stevel 	(void) strncpy(rootdir, execname, sizeof (rootdir));
    481      0   stevel 	rootdir[sizeof (rootdir) - 1] = '\0';
    482      0   stevel 	(void) strdirname(rootdir);
    483      0   stevel 
    484      0   stevel 	if (strcmp(strbasename(rootdir), "sparcv9") == 0 ||
    485      0   stevel 	    strcmp(strbasename(rootdir), "sparcv7") == 0 ||
    486      0   stevel 	    strcmp(strbasename(rootdir), "amd64") == 0 ||
    487      0   stevel 	    strcmp(strbasename(rootdir), "i86") == 0)
    488      0   stevel 		(void) strdirname(rootdir);
    489      0   stevel 
    490      0   stevel 	if (strcmp(strbasename(rootdir), "bin") == 0) {
    491      0   stevel 		(void) strdirname(rootdir);
    492      0   stevel 		if (strcmp(strbasename(rootdir), "usr") == 0)
    493      0   stevel 			(void) strdirname(rootdir);
    494      0   stevel 	} else
    495      0   stevel 		(void) strcpy(rootdir, "/");
    496      0   stevel 
    497      0   stevel 	mdb.m_root = rootdir;
    498      0   stevel 
    499      0   stevel 	mdb.m_rminfo.mi_dvers = MDB_API_VERSION;
    500      0   stevel 	mdb.m_rminfo.mi_dcmds = mdb_dcmd_builtins;
    501      0   stevel 	mdb.m_rminfo.mi_walkers = NULL;
    502      0   stevel 
    503      0   stevel 	(void) mdb_nv_create(&mdb.m_rmod.mod_walkers, UM_SLEEP);
    504      0   stevel 	(void) mdb_nv_create(&mdb.m_rmod.mod_dcmds, UM_SLEEP);
    505      0   stevel 
    506      0   stevel 	mdb.m_rmod.mod_name = mdb.m_pname;
    507      0   stevel 	mdb.m_rmod.mod_info = &mdb.m_rminfo;
    508      0   stevel 
    509      0   stevel 	(void) mdb_nv_create(&mdb.m_disasms, UM_SLEEP);
    510      0   stevel 	(void) mdb_nv_create(&mdb.m_modules, UM_SLEEP);
    511      0   stevel 	(void) mdb_nv_create(&mdb.m_dcmds, UM_SLEEP);
    512      0   stevel 	(void) mdb_nv_create(&mdb.m_walkers, UM_SLEEP);
    513      0   stevel 	(void) mdb_nv_create(&mdb.m_nv, UM_SLEEP);
    514      0   stevel 
    515      0   stevel 	mdb.m_dot = mdb_nv_insert(&mdb.m_nv, ".", NULL, 0, MDB_NV_PERSIST);
    516      0   stevel 	mdb.m_rvalue = mdb_nv_insert(&mdb.m_nv, "0", NULL, 0, MDB_NV_PERSIST);
    517      0   stevel 
    518      0   stevel 	mdb.m_roffset =
    519      0   stevel 	    mdb_nv_insert(&mdb.m_nv, "1", &roff_disc, 0, MDB_NV_PERSIST);
    520      0   stevel 
    521      0   stevel 	mdb.m_proffset = mdb_nv_insert(&mdb.m_nv, "2", NULL, 0, MDB_NV_PERSIST);
    522      0   stevel 	mdb.m_rcount = mdb_nv_insert(&mdb.m_nv, "9", NULL, 0, MDB_NV_PERSIST);
    523      0   stevel 
    524      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "b", NULL, 0, MDB_NV_PERSIST);
    525      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "d", NULL, 0, MDB_NV_PERSIST);
    526      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "e", NULL, 0, MDB_NV_PERSIST);
    527      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "m", NULL, 0, MDB_NV_PERSIST);
    528      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "t", NULL, 0, MDB_NV_PERSIST);
    529      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "_", &psym_disc, 0, MDB_NV_PERSIST);
    530      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "hits", NULL, 0, MDB_NV_PERSIST);
    531      0   stevel 
    532      0   stevel 	(void) mdb_nv_insert(&mdb.m_nv, "thread", &thr_disc, 0,
    533      0   stevel 	    MDB_NV_PERSIST | MDB_NV_RDONLY);
    534      0   stevel 
    535      0   stevel 	mdb.m_prsym = mdb_gelf_symtab_create_mutable();
    536      0   stevel 
    537      0   stevel 	(void) mdb_nv_insert(&mdb.m_modules, mdb.m_pname, NULL,
    538      0   stevel 	    (uintptr_t)&mdb.m_rmod, MDB_NV_RDONLY);
    539      0   stevel 
    540      0   stevel 	for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
    541      0   stevel 		(void) mdb_module_add_dcmd(&mdb.m_rmod, dcp, 0);
    542      0   stevel 
    543      0   stevel 	for (i = 0; mdb_dis_builtins[i] != NULL; i++)
    544      0   stevel 		(void) mdb_dis_create(mdb_dis_builtins[i]);
    545      0   stevel 
    546      0   stevel 	mdb_macalias_create();
    547      0   stevel 
    548      0   stevel 	mdb_create_builtin_tgts();
    549      0   stevel 
    550      0   stevel 	(void) mdb_callb_add(NULL, MDB_CALLB_PROMPT, (mdb_callb_f)prompt_update,
    551      0   stevel 	    NULL);
    552      0   stevel 
    553      0   stevel #ifdef _KMDB
    554      0   stevel 	(void) mdb_nv_create(&mdb.m_dmodctl, UM_SLEEP);
    555      0   stevel #endif
    556      0   stevel 	mdb_lex_state_create(&frame0);
    557      0   stevel 
    558      0   stevel 	mdb_list_append(&mdb.m_flist, &frame0);
    559      0   stevel 	mdb.m_frame = &frame0;
    560      0   stevel }
    561      0   stevel 
    562      0   stevel void
    563      0   stevel mdb_destroy(void)
    564      0   stevel {
    565      0   stevel 	const mdb_dcmd_t *dcp;
    566      0   stevel 	mdb_var_t *v;
    567      0   stevel 	int unload_mode = MDB_MOD_SILENT;
    568      0   stevel 
    569      0   stevel #ifdef _KMDB
    570      0   stevel 	unload_mode |= MDB_MOD_DEFER;
    571      0   stevel #endif
    572      0   stevel 
    573      0   stevel 	mdb_intr_disable();
    574      0   stevel 
    575      0   stevel 	mdb_macalias_destroy();
    576      0   stevel 
    577      0   stevel 	/*
    578   5084  johnlev 	 * Some targets use modules during ->t_destroy, so do it first.
    579   5084  johnlev 	 */
    580   5084  johnlev 	if (mdb.m_target != NULL)
    581   5084  johnlev 		(void) mdb_tgt_destroy(mdb.m_target);
    582   5084  johnlev 
    583   5084  johnlev 	/*
    584      0   stevel 	 * Unload modules _before_ destroying the disassemblers since a
    585      0   stevel 	 * module that installs a disassembler should try to clean up after
    586      0   stevel 	 * itself.
    587      0   stevel 	 */
    588      0   stevel 	mdb_module_unload_all(unload_mode);
    589      0   stevel 
    590      0   stevel 	mdb_nv_rewind(&mdb.m_disasms);
    591      0   stevel 	while ((v = mdb_nv_advance(&mdb.m_disasms)) != NULL)
    592      0   stevel 		mdb_dis_destroy(mdb_nv_get_cookie(v));
    593      0   stevel 
    594      0   stevel 	mdb_callb_remove_all();
    595      0   stevel 
    596      0   stevel 	if (mdb.m_defdisasm != NULL)
    597      0   stevel 		strfree(mdb.m_defdisasm);
    598      0   stevel 
    599      0   stevel 	if (mdb.m_prsym != NULL)
    600      0   stevel 		mdb_gelf_symtab_destroy(mdb.m_prsym);
    601      0   stevel 
    602      0   stevel 	for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
    603      0   stevel 		(void) mdb_module_remove_dcmd(&mdb.m_rmod, dcp->dc_name);
    604      0   stevel 
    605      0   stevel 	mdb_nv_destroy(&mdb.m_nv);
    606      0   stevel 	mdb_nv_destroy(&mdb.m_walkers);
    607      0   stevel 	mdb_nv_destroy(&mdb.m_dcmds);
    608      0   stevel 	mdb_nv_destroy(&mdb.m_modules);
    609      0   stevel 	mdb_nv_destroy(&mdb.m_disasms);
    610      0   stevel 
    611      0   stevel 	mdb_free(mdb.m_ipathstr, MAXPATHLEN);
    612      0   stevel 	mdb_free(mdb.m_lpathstr, MAXPATHLEN);
    613      0   stevel 
    614      0   stevel 	if (mdb.m_ipath != NULL)
    615      0   stevel 		mdb_path_free(mdb.m_ipath, mdb.m_ipathlen);
    616      0   stevel 
    617      0   stevel 	if (mdb.m_lpath != NULL)
    618      0   stevel 		mdb_path_free(mdb.m_lpath, mdb.m_lpathlen);
    619      0   stevel 
    620      0   stevel 	if (mdb.m_in != NULL)
    621      0   stevel 		mdb_iob_destroy(mdb.m_in);
    622      0   stevel 
    623      0   stevel 	mdb_iob_destroy(mdb.m_out);
    624      0   stevel 	mdb.m_out = NULL;
    625      0   stevel 	mdb_iob_destroy(mdb.m_err);
    626      0   stevel 	mdb.m_err = NULL;
    627      0   stevel 
    628      0   stevel 	if (mdb.m_log != NULL)
    629      0   stevel 		mdb_io_rele(mdb.m_log);
    630      0   stevel 
    631      0   stevel 	mdb_lex_state_destroy(&frame0);
    632      0   stevel }
    633      0   stevel 
    634      0   stevel /*
    635      0   stevel  * The real main loop of the debugger: create a new execution frame on the
    636      0   stevel  * debugger stack, and while we have input available, call into the parser.
    637      0   stevel  */
    638      0   stevel int
    639      0   stevel mdb_run(void)
    640      0   stevel {
    641      0   stevel 	volatile int err;
    642      0   stevel 	mdb_frame_t f;
    643      0   stevel 
    644      0   stevel 	mdb_intr_disable();
    645      0   stevel 	mdb_frame_push(&f);
    646      0   stevel 
    647      0   stevel 	/*
    648      0   stevel 	 * This is a fresh mdb context, so ignore any pipe command we may have
    649      0   stevel 	 * inherited from the previous frame.
    650      0   stevel 	 */
    651      0   stevel 	f.f_pcmd = NULL;
    652      0   stevel 
    653      0   stevel 	if ((err = setjmp(f.f_pcb)) != 0) {
    654      0   stevel 		int pop = (mdb.m_in != NULL &&
    655      0   stevel 		    (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in)));
    656      0   stevel 		int fromcmd = (f.f_cp != NULL);
    657      0   stevel 
    658      0   stevel 		mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n",
    659      0   stevel 		    f.f_id, mdb_err2str(err));
    660      0   stevel 
    661      0   stevel 		/*
    662      0   stevel 		 * If a syntax error or other failure has occurred, pop all
    663      0   stevel 		 * input buffers pushed by commands executed in this frame.
    664      0   stevel 		 */
    665      0   stevel 		while (mdb_iob_stack_size(&f.f_istk) != 0) {
    666      0   stevel 			if (mdb.m_in != NULL)
    667      0   stevel 				mdb_iob_destroy(mdb.m_in);
    668      0   stevel 			mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
    669      0   stevel 			yylineno = mdb_iob_lineno(mdb.m_in);
    670      0   stevel 		}
    671      0   stevel 
    672      0   stevel 		/*
    673      0   stevel 		 * Reset standard output and the current frame to a known,
    674      0   stevel 		 * clean state, so we can continue execution.
    675      0   stevel 		 */
    676      0   stevel 		mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN);
    677      0   stevel 		mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
    678      0   stevel 		mdb_iob_discard(mdb.m_out);
    679      0   stevel 		mdb_frame_reset(&f);
    680      0   stevel 
    681      0   stevel 		/*
    682      0   stevel 		 * If there was an error writing to output, display a warning
    683      0   stevel 		 * message if this is the topmost frame.
    684      0   stevel 		 */
    685      0   stevel 		if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE)
    686      0   stevel 			mdb_warn("write failed");
    687      0   stevel 
    688      0   stevel 		/*
    689      0   stevel 		 * If an interrupt or quit signal is reported, we may have been
    690      0   stevel 		 * in the middle of typing or processing the command line:
    691      0   stevel 		 * print a newline and discard everything in the parser's iob.
    692      0   stevel 		 * Note that we do this after m_out has been reset, otherwise
    693      0   stevel 		 * we could trigger a pipe context switch or cause a write
    694      0   stevel 		 * to a broken pipe (in the case of a shell command) when
    695      0   stevel 		 * writing the newline.
    696      0   stevel 		 */
    697      0   stevel 		if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) {
    698      0   stevel 			mdb_iob_nl(mdb.m_out);
    699      0   stevel 			yydiscard();
    700      0   stevel 		}
    701      0   stevel 
    702      0   stevel 		/*
    703      0   stevel 		 * If we quit or abort using the output pager, reset the
    704      0   stevel 		 * line count on standard output back to zero.
    705      0   stevel 		 */
    706      0   stevel 		if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err))
    707      0   stevel 			mdb_iob_clearlines(mdb.m_out);
    708      0   stevel 
    709      0   stevel 		/*
    710      0   stevel 		 * If the user requested the debugger quit or abort back to
    711      0   stevel 		 * the top, or if standard input is a pipe or mdb_eval("..."),
    712      0   stevel 		 * then propagate the error up the debugger stack.
    713      0   stevel 		 */
    714      0   stevel 		if (MDB_ERR_IS_FATAL(err) || pop != 0 ||
    715      0   stevel 		    (err == MDB_ERR_PAGER && mdb.m_fmark != &f) ||
    716      0   stevel 		    (err == MDB_ERR_NOMEM && !fromcmd)) {
    717      0   stevel 			mdb_frame_pop(&f, err);
    718      0   stevel 			return (err);
    719      0   stevel 		}
    720      0   stevel 
    721      0   stevel 		/*
    722      0   stevel 		 * If we've returned here from a context where signals were
    723      0   stevel 		 * blocked (e.g. a signal handler), we can now unblock them.
    724      0   stevel 		 */
    725      0   stevel 		if (err == MDB_ERR_SIGINT)
    726      0   stevel 			(void) mdb_signal_unblock(SIGINT);
    727      0   stevel 	} else
    728      0   stevel 		mdb_intr_enable();
    729      0   stevel 
    730      0   stevel 	for (;;) {
    731      0   stevel 		while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) &
    732      0   stevel 		    (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) {
    733      0   stevel 			if (mdb.m_depth == 1 &&
    734      0   stevel 			    mdb_iob_stack_size(&f.f_istk) == 0) {
    735      0   stevel 				mdb_iob_clearlines(mdb.m_out);
    736      0   stevel 				mdb_tgt_periodic(mdb.m_target);
    737      0   stevel 			}
    738      0   stevel 
    739      0   stevel 			(void) yyparse();
    740      0   stevel 		}
    741      0   stevel 
    742      0   stevel 		if (mdb.m_in != NULL) {
    743      0   stevel 			if (mdb_iob_err(mdb.m_in)) {
    744      0   stevel 				warn("error reading input stream %s\n",
    745      0   stevel 				    mdb_iob_name(mdb.m_in));
    746      0   stevel 			}
    747      0   stevel 			mdb_iob_destroy(mdb.m_in);
    748      0   stevel 			mdb.m_in = NULL;
    749      0   stevel 		}
    750      0   stevel 
    751      0   stevel 		if (mdb_iob_stack_size(&f.f_istk) == 0)
    752      0   stevel 			break; /* return when we're out of input */
    753      0   stevel 
    754      0   stevel 		mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
    755      0   stevel 		yylineno = mdb_iob_lineno(mdb.m_in);
    756      0   stevel 	}
    757      0   stevel 
    758      0   stevel 	mdb_frame_pop(&f, 0);
    759      0   stevel 
    760      0   stevel 	/*
    761      0   stevel 	 * The value of '.' is a per-frame attribute, to preserve it properly
    762      0   stevel 	 * when switching frames.  But in the case of calling mdb_run()
    763      0   stevel 	 * explicitly (such as through mdb_eval), we want to propagate the value
    764      0   stevel 	 * of '.' to the parent.
    765      0   stevel 	 */
    766      0   stevel 	mdb_nv_set_value(mdb.m_dot, f.f_dot);
    767      0   stevel 
    768      0   stevel 	return (0);
    769      0   stevel }
    770      0   stevel 
    771      0   stevel /*
    772      0   stevel  * The read-side of the pipe executes this service routine.  We simply call
    773      0   stevel  * mdb_run to create a new frame on the execution stack and run the MDB parser,
    774      0   stevel  * and then propagate any error code back to the previous frame.
    775      0   stevel  */
    776      0   stevel static int
    777      0   stevel runsvc(void)
    778      0   stevel {
    779      0   stevel 	int err = mdb_run();
    780      0   stevel 
    781      0   stevel 	if (err != 0) {
    782      0   stevel 		mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n",
    783      0   stevel 		    mdb_err2str(err));
    784      0   stevel 		longjmp(mdb.m_frame->f_pcb, err);
    785      0   stevel 	}
    786      0   stevel 
    787      0   stevel 	return (err);
    788      0   stevel }
    789      0   stevel 
    790      0   stevel /*
    791      0   stevel  * Read-side pipe service routine: if we longjmp here, just return to the read
    792      0   stevel  * routine because now we have more data to consume.  Otherwise:
    793      0   stevel  * (1) if ctx_data is non-NULL, longjmp to the write-side to produce more data;
    794      0   stevel  * (2) if wriob is NULL, there is no writer but this is the first read, so we
    795      0   stevel  *     can just execute mdb_run() to completion on the current stack;
    796      0   stevel  * (3) if (1) and (2) are false, then there is a writer and this is the first
    797      0   stevel  *     read, so create a co-routine context to execute mdb_run().
    798      0   stevel  */
    799      0   stevel /*ARGSUSED*/
    800      0   stevel static void
    801      0   stevel rdsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
    802      0   stevel {
    803      0   stevel 	if (setjmp(ctx->ctx_rpcb) == 0) {
    804      0   stevel 		/*
    805      0   stevel 		 * Save the current standard input into the pipe context, and
    806      0   stevel 		 * reset m_in to point to the pipe.  We will restore it on
    807      0   stevel 		 * the way back in wrsvc() below.
    808      0   stevel 		 */
    809      0   stevel 		ctx->ctx_iob = mdb.m_in;
    810      0   stevel 		mdb.m_in = rdiob;
    811      0   stevel 
    812      0   stevel 		ctx->ctx_rptr = mdb.m_frame;
    813      0   stevel 		if (ctx->ctx_wptr != NULL)
    814      0   stevel 			mdb_frame_switch(ctx->ctx_wptr);
    815      0   stevel 
    816      0   stevel 		if (ctx->ctx_data != NULL)
    817      0   stevel 			longjmp(ctx->ctx_wpcb, 1);
    818      0   stevel 		else if (wriob == NULL)
    819      0   stevel 			(void) runsvc();
    820      0   stevel 		else if ((ctx->ctx_data = mdb_context_create(runsvc)) != NULL)
    821      0   stevel 			mdb_context_switch(ctx->ctx_data);
    822      0   stevel 		else
    823      0   stevel 			mdb_warn("failed to create pipe context");
    824      0   stevel 	}
    825      0   stevel }
    826      0   stevel 
    827      0   stevel /*
    828      0   stevel  * Write-side pipe service routine: if we longjmp here, just return to the
    829      0   stevel  * write routine because now we have free space in the pipe buffer for writing;
    830      0   stevel  * otherwise longjmp to the read-side to consume data and create space for us.
    831      0   stevel  */
    832      0   stevel /*ARGSUSED*/
    833      0   stevel static void
    834      0   stevel wrsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
    835      0   stevel {
    836      0   stevel 	if (setjmp(ctx->ctx_wpcb) == 0) {
    837      0   stevel 		ctx->ctx_wptr = mdb.m_frame;
    838      0   stevel 		if (ctx->ctx_rptr != NULL)
    839      0   stevel 			mdb_frame_switch(ctx->ctx_rptr);
    840      0   stevel 
    841      0   stevel 		mdb.m_in = ctx->ctx_iob;
    842      0   stevel 		longjmp(ctx->ctx_rpcb, 1);
    843      0   stevel 	}
    844      0   stevel }
    845      0   stevel 
    846      0   stevel /*
    847      0   stevel  * Call the current frame's mdb command.  This entry point is used by the
    848      0   stevel  * MDB parser to actually execute a command once it has successfully parsed
    849      0   stevel  * a line of input.  The command is waiting for us in the current frame.
    850      0   stevel  * We loop through each command on the list, executing its dcmd with the
    851      0   stevel  * appropriate argument.  If the command has a successor, we know it had
    852      0   stevel  * a | operator after it, and so we need to create a pipe and replace
    853      0   stevel  * stdout with the pipe's output buffer.
    854      0   stevel  */
    855      0   stevel int
    856      0   stevel mdb_call(uintmax_t addr, uintmax_t count, uint_t flags)
    857      0   stevel {
    858      0   stevel 	mdb_frame_t *fp = mdb.m_frame;
    859      0   stevel 	mdb_cmd_t *cp, *ncp;
    860      0   stevel 	mdb_iob_t *iobs[2];
    861      0   stevel 	int status, err = 0;
    862      0   stevel 	jmp_buf pcb;
    863      0   stevel 
    864      0   stevel 	if (mdb_iob_isapipe(mdb.m_in))
    865      0   stevel 		yyerror("syntax error");
    866      0   stevel 
    867      0   stevel 	mdb_intr_disable();
    868      0   stevel 	fp->f_cp = mdb_list_next(&fp->f_cmds);
    869      0   stevel 
    870      0   stevel 	if (flags & DCMD_LOOP)
    871      0   stevel 		flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */
    872      0   stevel 
    873      0   stevel 	for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) {
    874      0   stevel 		if (mdb_list_next(cp) != NULL) {
    875      0   stevel 			mdb_iob_pipe(iobs, rdsvc, wrsvc);
    876      0   stevel 
    877      0   stevel 			mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
    878      0   stevel 			mdb.m_in = iobs[MDB_IOB_RDIOB];
    879      0   stevel 
    880      0   stevel 			mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0);
    881      0   stevel 			mdb.m_out = iobs[MDB_IOB_WRIOB];
    882      0   stevel 
    883      0   stevel 			ncp = mdb_list_next(cp);
    884      0   stevel 			mdb_vcb_inherit(cp, ncp);
    885      0   stevel 
    886      0   stevel 			bcopy(fp->f_pcb, pcb, sizeof (jmp_buf));
    887      0   stevel 			ASSERT(fp->f_pcmd == NULL);
    888      0   stevel 			fp->f_pcmd = ncp;
    889      0   stevel 
    890   3277       af 			mdb_frame_set_pipe(fp);
    891   3277       af 
    892      0   stevel 			if ((err = setjmp(fp->f_pcb)) == 0) {
    893      0   stevel 				status = mdb_call_idcmd(cp->c_dcmd, addr, count,
    894      0   stevel 				    flags | DCMD_PIPE_OUT, &cp->c_argv,
    895      0   stevel 				    &cp->c_addrv, cp->c_vcbs);
    896      0   stevel 
    897      0   stevel 				ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]);
    898      0   stevel 				ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]);
    899      0   stevel 			} else {
    900      0   stevel 				mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught "
    901      0   stevel 				    "error %s from pipeline\n", fp->f_id,
    902      0   stevel 				    mdb_err2str(err));
    903      0   stevel 			}
    904      0   stevel 
    905      0   stevel 			if (err != 0 || DCMD_ABORTED(status)) {
    906      0   stevel 				mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR);
    907      0   stevel 				mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR);
    908      0   stevel 			} else {
    909      0   stevel 				mdb_iob_flush(mdb.m_out);
    910      0   stevel 				(void) mdb_iob_ctl(mdb.m_out, I_FLUSH,
    911      0   stevel 				    (void *)FLUSHW);
    912      0   stevel 			}
    913   3277       af 
    914   3277       af 			mdb_frame_clear_pipe(fp);
    915      0   stevel 
    916      0   stevel 			mdb_iob_destroy(mdb.m_out);
    917      0   stevel 			mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk);
    918      0   stevel 
    919      0   stevel 			if (mdb.m_in != NULL)
    920      0   stevel 				mdb_iob_destroy(mdb.m_in);
    921      0   stevel 
    922      0   stevel 			mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
    923      0   stevel 			yylineno = mdb_iob_lineno(mdb.m_in);
    924      0   stevel 
    925      0   stevel 			fp->f_pcmd = NULL;
    926      0   stevel 			bcopy(pcb, fp->f_pcb, sizeof (jmp_buf));
    927      0   stevel 
    928      0   stevel 			if (MDB_ERR_IS_FATAL(err))
    929      0   stevel 				longjmp(fp->f_pcb, err);
    930      0   stevel 
    931      0   stevel 			if (err != 0 || DCMD_ABORTED(status) ||
    932      0   stevel 			    mdb_addrvec_length(&ncp->c_addrv) == 0)
    933      0   stevel 				break;
    934      0   stevel 
    935      0   stevel 			addr = mdb_nv_get_value(mdb.m_dot);
    936      0   stevel 			count = 1;
    937      0   stevel 			flags = 0;
    938      0   stevel 
    939      0   stevel 		} else {
    940      0   stevel 			mdb_intr_enable();
    941      0   stevel 			(void) mdb_call_idcmd(cp->c_dcmd, addr, count, flags,
    942      0   stevel 			    &cp->c_argv, &cp->c_addrv, cp->c_vcbs);
    943      0   stevel 			mdb_intr_disable();
    944      0   stevel 		}
    945      0   stevel 
    946      0   stevel 		fp->f_cp = mdb_list_next(cp);
    947      0   stevel 		mdb_cmd_reset(cp);
    948      0   stevel 	}
    949      0   stevel 
    950      0   stevel 	/*
    951      0   stevel 	 * If our last-command list is non-empty, destroy it.  Then copy the
    952      0   stevel 	 * current frame's cmd list to the m_lastc list and reset the frame.
    953      0   stevel 	 */
    954      0   stevel 	while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) {
    955      0   stevel 		mdb_list_delete(&mdb.m_lastc, cp);
    956      0   stevel 		mdb_cmd_destroy(cp);
    957      0   stevel 	}
    958      0   stevel 
    959      0   stevel 	mdb_list_move(&fp->f_cmds, &mdb.m_lastc);
    960      0   stevel 	mdb_frame_reset(fp);
    961      0   stevel 	mdb_intr_enable();
    962      0   stevel 	return (err == 0);
    963      0   stevel }
    964      0   stevel 
    965      0   stevel uintmax_t
    966      0   stevel mdb_dot_incr(const char *op)
    967      0   stevel {
    968      0   stevel 	uintmax_t odot, ndot;
    969      0   stevel 
    970      0   stevel 	odot = mdb_nv_get_value(mdb.m_dot);
    971      0   stevel 	ndot = odot + mdb.m_incr;
    972      0   stevel 
    973      0   stevel 	if ((odot ^ ndot) & 0x8000000000000000ull)
    974      0   stevel 		yyerror("'%s' would cause '.' to overflow\n", op);
    975      0   stevel 
    976      0   stevel 	return (ndot);
    977      0   stevel }
    978      0   stevel 
    979      0   stevel uintmax_t
    980      0   stevel mdb_dot_decr(const char *op)
    981      0   stevel {
    982      0   stevel 	uintmax_t odot, ndot;
    983      0   stevel 
    984      0   stevel 	odot = mdb_nv_get_value(mdb.m_dot);
    985      0   stevel 	ndot = odot - mdb.m_incr;
    986      0   stevel 
    987      0   stevel 	if (ndot > odot)
    988      0   stevel 		yyerror("'%s' would cause '.' to underflow\n", op);
    989      0   stevel 
    990      0   stevel 	return (ndot);
    991      0   stevel }
    992      0   stevel 
    993      0   stevel mdb_iwalker_t *
    994      0   stevel mdb_walker_lookup(const char *s)
    995      0   stevel {
    996      0   stevel 	const char *p = strchr(s, '`');
    997      0   stevel 	mdb_var_t *v;
    998      0   stevel 
    999      0   stevel 	if (p != NULL) {
   1000      0   stevel 		size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
   1001      0   stevel 		char mname[MDB_NV_NAMELEN];
   1002      0   stevel 		mdb_module_t *mod;
   1003      0   stevel 
   1004      0   stevel 		(void) strncpy(mname, s, nbytes);
   1005      0   stevel 		mname[nbytes] = '\0';
   1006      0   stevel 
   1007      0   stevel 		if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
   1008      0   stevel 			(void) set_errno(EMDB_NOMOD);
   1009      0   stevel 			return (NULL);
   1010      0   stevel 		}
   1011      0   stevel 
   1012      0   stevel 		mod = mdb_nv_get_cookie(v);
   1013      0   stevel 
   1014      0   stevel 		if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL)
   1015      0   stevel 			return (mdb_nv_get_cookie(v));
   1016      0   stevel 
   1017      0   stevel 	} else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL)
   1018      0   stevel 		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
   1019      0   stevel 
   1020      0   stevel 	(void) set_errno(EMDB_NOWALK);
   1021      0   stevel 	return (NULL);
   1022      0   stevel }
   1023      0   stevel 
   1024      0   stevel mdb_idcmd_t *
   1025      0   stevel mdb_dcmd_lookup(const char *s)
   1026      0   stevel {
   1027      0   stevel 	const char *p = strchr(s, '`');
   1028      0   stevel 	mdb_var_t *v;
   1029      0   stevel 
   1030      0   stevel 	if (p != NULL) {
   1031      0   stevel 		size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
   1032      0   stevel 		char mname[MDB_NV_NAMELEN];
   1033      0   stevel 		mdb_module_t *mod;
   1034      0   stevel 
   1035      0   stevel 		(void) strncpy(mname, s, nbytes);
   1036      0   stevel 		mname[nbytes] = '\0';
   1037      0   stevel 
   1038      0   stevel 		if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
   1039      0   stevel 			(void) set_errno(EMDB_NOMOD);
   1040      0   stevel 			return (NULL);
   1041      0   stevel 		}
   1042      0   stevel 
   1043      0   stevel 		mod = mdb_nv_get_cookie(v);
   1044      0   stevel 
   1045      0   stevel 		if ((v = mdb_nv_lookup(&mod->mod_dcmds, ++p)) != NULL)
   1046      0   stevel 			return (mdb_nv_get_cookie(v));
   1047      0   stevel 
   1048      0   stevel 	} else if ((v = mdb_nv_lookup(&mdb.m_dcmds, s)) != NULL)
   1049      0   stevel 		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
   1050      0   stevel 
   1051      0   stevel 	(void) set_errno(EMDB_NODCMD);
   1052      0   stevel 	return (NULL);
   1053      0   stevel }
   1054      0   stevel 
   1055      0   stevel void
   1056      0   stevel mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob)
   1057      0   stevel {
   1058      0   stevel 	const char *prefix = "", *usage = "";
   1059      0   stevel 	char name0 = idcp->idc_name[0];
   1060      0   stevel 
   1061      0   stevel 	if (idcp->idc_usage != NULL) {
   1062      0   stevel 		if (idcp->idc_usage[0] == ':') {
   1063      0   stevel 			if (name0 != ':' && name0 != '$')
   1064      0   stevel 				prefix = "address::";
   1065      0   stevel 			else
   1066      0   stevel 				prefix = "address";
   1067      0   stevel 			usage = &idcp->idc_usage[1];
   1068      0   stevel 
   1069      0   stevel 		} else if (idcp->idc_usage[0] == '?') {
   1070      0   stevel 			if (name0 != ':' && name0 != '$')
   1071      0   stevel 				prefix = "[address]::";
   1072      0   stevel 			else
   1073      0   stevel 				prefix = "[address]";
   1074      0   stevel 			usage = &idcp->idc_usage[1];
   1075      0   stevel 
   1076      0   stevel 		} else
   1077      0   stevel 			usage = idcp->idc_usage;
   1078      0   stevel 	}
   1079      0   stevel 
   1080      0   stevel 	mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage);
   1081      0   stevel 
   1082      0   stevel 	if (idcp->idc_help != NULL) {
   1083      0   stevel 		mdb_iob_printf(iob, "%s: try '::help %s' for more "
   1084      0   stevel 		    "information\n", mdb.m_pname, idcp->idc_name);
   1085      0   stevel 	}
   1086      0   stevel }
   1087      0   stevel 
   1088      0   stevel static mdb_idcmd_t *
   1089      0   stevel dcmd_ndef(const mdb_idcmd_t *idcp)
   1090      0   stevel {
   1091      0   stevel 	mdb_var_t *v = mdb_nv_get_ndef(idcp->idc_var);
   1092      0   stevel 
   1093      0   stevel 	if (v != NULL)
   1094      0   stevel 		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
   1095      0   stevel 
   1096      0   stevel 	return (NULL);
   1097      0   stevel }
   1098      0   stevel 
   1099      0   stevel static int
   1100      0   stevel dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags,
   1101      0   stevel     int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs)
   1102      0   stevel {
   1103      0   stevel 	int status;
   1104      0   stevel 
   1105      0   stevel 	mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n",
   1106      0   stevel 	    idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr);
   1107      0   stevel 
   1108      0   stevel 	if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) {
   1109      0   stevel 		mdb_dcmd_usage(idcp, mdb.m_err);
   1110      0   stevel 		goto done;
   1111      0   stevel 	}
   1112      0   stevel 
   1113      0   stevel 	while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL)
   1114      0   stevel 		status = idcp->idc_funcp(addr, flags, argc, argv);
   1115      0   stevel 
   1116      0   stevel 	if (status == DCMD_USAGE)
   1117      0   stevel 		mdb_dcmd_usage(idcp, mdb.m_err);
   1118      0   stevel 
   1119      0   stevel 	if (status == DCMD_NEXT)
   1120      0   stevel 		status = DCMD_OK;
   1121      0   stevel done:
   1122      0   stevel 	/*
   1123      0   stevel 	 * If standard output is a pipe and there are vcbs active, we need to
   1124      0   stevel 	 * flush standard out and the write-side of the pipe.  The reasons for
   1125      0   stevel 	 * this are explained in more detail in mdb_vcb.c.
   1126      0   stevel 	 */
   1127      0   stevel 	if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) {
   1128      0   stevel 		mdb_iob_flush(mdb.m_out);
   1129      0   stevel 		(void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW);
   1130      0   stevel 	}
   1131      0   stevel 
   1132      0   stevel 	return (status);
   1133      0   stevel }
   1134      0   stevel 
   1135      0   stevel /*
   1136      0   stevel  * Call an internal dcmd directly: this code is used by module API functions
   1137      0   stevel  * that need to execute dcmds, and by mdb_call() above.
   1138      0   stevel  */
   1139      0   stevel int
   1140      0   stevel mdb_call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count,
   1141      0   stevel     uint_t flags, mdb_argvec_t *avp, mdb_addrvec_t *adp, mdb_vcb_t *vcbs)
   1142      0   stevel {
   1143      0   stevel 	int is_exec = (strcmp(idcp->idc_name, "$<") == 0);
   1144      0   stevel 	mdb_arg_t *argv;
   1145      0   stevel 	int argc;
   1146      0   stevel 	uintmax_t i;
   1147      0   stevel 	int status;
   1148      0   stevel 
   1149      0   stevel 	/*
   1150      0   stevel 	 * Update the values of dot and the most recent address and count
   1151      0   stevel 	 * to the values of our input parameters.
   1152      0   stevel 	 */
   1153      0   stevel 	mdb_nv_set_value(mdb.m_dot, addr);
   1154      0   stevel 	mdb.m_raddr = addr;
   1155      0   stevel 	mdb.m_dcount = count;
   1156      0   stevel 
   1157      0   stevel 	/*
   1158      0   stevel 	 * Here the adb(1) man page lies: '9' is only set to count
   1159      0   stevel 	 * when the command is $<, not when it's $<<.
   1160      0   stevel 	 */
   1161      0   stevel 	if (is_exec)
   1162      0   stevel 		mdb_nv_set_value(mdb.m_rcount, count);
   1163      0   stevel 
   1164      0   stevel 	/*
   1165      0   stevel 	 * We can now return if the repeat count is zero.
   1166      0   stevel 	 */
   1167      0   stevel 	if (count == 0)
   1168      0   stevel 		return (DCMD_OK);
   1169      0   stevel 
   1170      0   stevel 	/*
   1171      0   stevel 	 * To guard against bad dcmds, we avoid passing the actual argv that
   1172      0   stevel 	 * we will use to free argument strings directly to the dcmd.  Instead,
   1173      0   stevel 	 * we pass a copy that will be garbage collected automatically.
   1174      0   stevel 	 */
   1175      0   stevel 	argc = avp->a_nelems;
   1176      0   stevel 	argv = mdb_alloc(sizeof (mdb_arg_t) * argc, UM_SLEEP | UM_GC);
   1177      0   stevel 	bcopy(avp->a_data, argv, sizeof (mdb_arg_t) * argc);
   1178      0   stevel 
   1179      0   stevel 	if (mdb_addrvec_length(adp) != 0) {
   1180      0   stevel 		flags |= DCMD_PIPE | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC;
   1181      0   stevel 		addr = mdb_addrvec_shift(adp);
   1182      0   stevel 		mdb_nv_set_value(mdb.m_dot, addr);
   1183      0   stevel 		mdb_vcb_propagate(vcbs);
   1184      0   stevel 		count = 1;
   1185      0   stevel 	}
   1186      0   stevel 
   1187      0   stevel 	status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
   1188      0   stevel 	if (DCMD_ABORTED(status))
   1189      0   stevel 		goto done;
   1190      0   stevel 
   1191      0   stevel 	/*
   1192      0   stevel 	 * If the command is $< and we're not receiving input from a pipe, we
   1193      0   stevel 	 * ignore the repeat count and just return since the macro file is now
   1194      0   stevel 	 * pushed on to the input stack.
   1195      0   stevel 	 */
   1196      0   stevel 	if (is_exec && mdb_addrvec_length(adp) == 0)
   1197      0   stevel 		goto done;
   1198      0   stevel 
   1199      0   stevel 	/*
   1200      0   stevel 	 * If we're going to loop, we've already executed the dcmd once,
   1201      0   stevel 	 * so clear the LOOPFIRST flag before proceeding.
   1202      0   stevel 	 */
   1203      0   stevel 	if (flags & DCMD_LOOP)
   1204      0   stevel 		flags &= ~DCMD_LOOPFIRST;
   1205      0   stevel 
   1206      0   stevel 	for (i = 1; i < count; i++) {
   1207      0   stevel 		addr = mdb_dot_incr(",");
   1208      0   stevel 		mdb_nv_set_value(mdb.m_dot, addr);
   1209      0   stevel 		status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
   1210      0   stevel 		if (DCMD_ABORTED(status))
   1211      0   stevel 			goto done;
   1212      0   stevel 	}
   1213      0   stevel 
   1214      0   stevel 	while (mdb_addrvec_length(adp) != 0) {
   1215      0   stevel 		addr = mdb_addrvec_shift(adp);
   1216      0   stevel 		mdb_nv_set_value(mdb.m_dot, addr);
   1217      0   stevel 		mdb_vcb_propagate(vcbs);
   1218      0   stevel 		status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
   1219      0   stevel 		if (DCMD_ABORTED(status))
   1220      0   stevel 			goto done;
   1221      0   stevel 	}
   1222      0   stevel done:
   1223      0   stevel 	mdb_iob_nlflush(mdb.m_out);
   1224      0   stevel 	return (status);
   1225      0   stevel }
   1226      0   stevel 
   1227      0   stevel void
   1228      0   stevel mdb_intr_enable(void)
   1229      0   stevel {
   1230      0   stevel 	ASSERT(mdb.m_intr >= 1);
   1231      0   stevel 	if (mdb.m_intr == 1 && mdb.m_pend != 0) {
   1232      0   stevel 		(void) mdb_signal_block(SIGINT);
   1233      0   stevel 		mdb.m_intr = mdb.m_pend = 0;
   1234      0   stevel 		mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n");
   1235      0   stevel 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT);
   1236      0   stevel 	} else
   1237      0   stevel 		mdb.m_intr--;
   1238      0   stevel }
   1239      0   stevel 
   1240      0   stevel void
   1241      0   stevel mdb_intr_disable(void)
   1242      0   stevel {
   1243      0   stevel 	mdb.m_intr++;
   1244      0   stevel 	ASSERT(mdb.m_intr >= 1);
   1245      0   stevel }
   1246      0   stevel 
   1247      0   stevel /*
   1248      0   stevel  * Create an encoded string representing the internal user-modifiable
   1249      0   stevel  * configuration of the debugger and return a pointer to it.  The string can be
   1250      0   stevel  * used to initialize another instance of the debugger with the same
   1251      0   stevel  * configuration as this one.
   1252      0   stevel  */
   1253      0   stevel char *
   1254      0   stevel mdb_get_config(void)
   1255      0   stevel {
   1256      0   stevel 	size_t r, n = 0;
   1257      0   stevel 	char *s = NULL;
   1258      0   stevel 
   1259      0   stevel 	while ((r = mdb_snprintf(s, n,
   1260      0   stevel 	    "%x;%x;%x;%x;%x;%x;%lx;%x;%x;%s;%s;%s;%s;%s",
   1261      0   stevel 	    mdb.m_tgtflags, mdb.m_flags, mdb.m_debug, mdb.m_radix, mdb.m_nargs,
   1262      0   stevel 	    mdb.m_histlen, (ulong_t)mdb.m_symdist, mdb.m_execmode,
   1263      0   stevel 	    mdb.m_forkmode, mdb.m_root, mdb.m_termtype, mdb.m_ipathstr,
   1264      0   stevel 	    mdb.m_lpathstr, mdb.m_prompt)) > n) {
   1265      0   stevel 
   1266      0   stevel 		mdb_free(s, n);
   1267      0   stevel 		n = r + 1;
   1268      0   stevel 		s = mdb_alloc(r + 1, UM_SLEEP);
   1269      0   stevel 	}
   1270      0   stevel 
   1271      0   stevel 	return (s);
   1272      0   stevel }
   1273      0   stevel 
   1274      0   stevel /*
   1275      0   stevel  * Decode a configuration string created with mdb_get_config() and reset the
   1276      0   stevel  * appropriate parts of the global mdb_t accordingly.
   1277      0   stevel  */
   1278      0   stevel void
   1279      0   stevel mdb_set_config(const char *s)
   1280      0   stevel {
   1281      0   stevel 	const char *p;
   1282      0   stevel 	size_t len;
   1283      0   stevel 
   1284      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1285      0   stevel 		mdb.m_tgtflags = strntoul(s, (size_t)(p - s), 16);
   1286      0   stevel 		s = p + 1;
   1287      0   stevel 	}
   1288      0   stevel 
   1289      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1290      0   stevel 		mdb.m_flags = strntoul(s, (size_t)(p - s), 16);
   1291      0   stevel 		mdb.m_flags &= ~(MDB_FL_LOG | MDB_FL_LATEST);
   1292      0   stevel 		s = p + 1;
   1293      0   stevel 	}
   1294      0   stevel 
   1295      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1296      0   stevel 		mdb.m_debug = strntoul(s, (size_t)(p - s), 16);
   1297      0   stevel 		s = p + 1;
   1298      0   stevel 	}
   1299      0   stevel 
   1300      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1301      0   stevel 		mdb.m_radix = (int)strntoul(s, (size_t)(p - s), 16);
   1302      0   stevel 		if (mdb.m_radix < 2 || mdb.m_radix > 16)
   1303      0   stevel 			mdb.m_radix = MDB_DEF_RADIX;
   1304      0   stevel 		s = p + 1;
   1305      0   stevel 	}
   1306      0   stevel 
   1307      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1308      0   stevel 		mdb.m_nargs = (int)strntoul(s, (size_t)(p - s), 16);
   1309      0   stevel 		mdb.m_nargs = MAX(mdb.m_nargs, 0);
   1310      0   stevel 		s = p + 1;
   1311      0   stevel 	}
   1312      0   stevel 
   1313      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1314      0   stevel 		mdb.m_histlen = (int)strntoul(s, (size_t)(p - s), 16);
   1315      0   stevel 		mdb.m_histlen = MAX(mdb.m_histlen, 1);
   1316      0   stevel 		s = p + 1;
   1317      0   stevel 	}
   1318      0   stevel 
   1319      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1320      0   stevel 		mdb.m_symdist = strntoul(s, (size_t)(p - s), 16);
   1321      0   stevel 		s = p + 1;
   1322      0   stevel 	}
   1323      0   stevel 
   1324      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1325      0   stevel 		mdb.m_execmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
   1326      0   stevel 		if (mdb.m_execmode > MDB_EM_FOLLOW)
   1327      0   stevel 			mdb.m_execmode = MDB_EM_ASK;
   1328      0   stevel 		s = p + 1;
   1329      0   stevel 	}
   1330      0   stevel 
   1331      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1332      0   stevel 		mdb.m_forkmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
   1333      0   stevel 		if (mdb.m_forkmode > MDB_FM_CHILD)
   1334      0   stevel 			mdb.m_forkmode = MDB_FM_ASK;
   1335      0   stevel 		s = p + 1;
   1336      0   stevel 	}
   1337      0   stevel 
   1338      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1339      0   stevel 		mdb.m_root = strndup(s, (size_t)(p - s));
   1340      0   stevel 		s = p + 1;
   1341      0   stevel 	}
   1342      0   stevel 
   1343      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1344      0   stevel 		mdb.m_termtype = strndup(s, (size_t)(p - s));
   1345      0   stevel 		s = p + 1;
   1346      0   stevel 	}
   1347      0   stevel 
   1348      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1349      0   stevel 		size_t len = MIN(sizeof (mdb.m_ipathstr) - 1, p - s);
   1350  11053    Surya 		(void) strncpy(mdb.m_ipathstr, s, len);
   1351      0   stevel 		mdb.m_ipathstr[len] = '\0';
   1352      0   stevel 		s = p + 1;
   1353      0   stevel 	}
   1354      0   stevel 
   1355      0   stevel 	if ((p = strchr(s, ';')) != NULL) {
   1356      0   stevel 		size_t len = MIN(sizeof (mdb.m_lpathstr) - 1, p - s);
   1357  11053    Surya 		(void) strncpy(mdb.m_lpathstr, s, len);
   1358      0   stevel 		mdb.m_lpathstr[len] = '\0';
   1359      0   stevel 		s = p + 1;
   1360      0   stevel 	}
   1361      0   stevel 
   1362      0   stevel 	p = s + strlen(s);
   1363      0   stevel 	len = MIN(MDB_PROMPTLEN, (size_t)(p - s));
   1364      0   stevel 	(void) strncpy(mdb.m_prompt, s, len);
   1365      0   stevel 	mdb.m_prompt[len] = '\0';
   1366      0   stevel 	mdb.m_promptlen = len;
   1367      0   stevel }
   1368      0   stevel 
   1369      0   stevel mdb_module_t *
   1370      0   stevel mdb_get_module(void)
   1371      0   stevel {
   1372      0   stevel 	if (mdb.m_lmod)
   1373      0   stevel 		return (mdb.m_lmod);
   1374      0   stevel 
   1375   5084  johnlev 	if (mdb.m_frame == NULL)
   1376   5084  johnlev 		return (NULL);
   1377   5084  johnlev 
   1378   5084  johnlev 	if (mdb.m_frame->f_wcbs && mdb.m_frame->f_wcbs->w_walker &&
   1379   5084  johnlev 	    mdb.m_frame->f_wcbs->w_walker->iwlk_modp)
   1380   5084  johnlev 		return (mdb.m_frame->f_wcbs->w_walker->iwlk_modp);
   1381   5084  johnlev 
   1382   5084  johnlev 	if (mdb.m_frame->f_cp && mdb.m_frame->f_cp->c_dcmd)
   1383      0   stevel 		return (mdb.m_frame->f_cp->c_dcmd->idc_modp);
   1384      0   stevel 
   1385      0   stevel 	return (NULL);
   1386      0   stevel }
   1387